Minecraft 25w20a protocol support

This commit is contained in:
md_5 2025-05-17 16:01:00 +10:00
parent a336efb8fa
commit 69e4872f40
No known key found for this signature in database
GPG Key ID: E8E901AC7C617C11
67 changed files with 1530 additions and 41 deletions

View File

@ -31,6 +31,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-dialog</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-event</artifactId>

View File

@ -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);
}

View File

@ -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<String, String> data;
/**
* Cancelled state.
*/
private boolean cancelled;
}

View File

@ -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,
}
}

View File

@ -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;
}
}

View File

@ -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.
*

28
dialog/LICENSE Normal file
View File

@ -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.

35
dialog/README.md Normal file
View File

@ -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() );
}
}
```

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

36
dialog/pom.xml Normal file
View File

@ -0,0 +1,36 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-dialog</artifactId>
<version>1.21-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Dialog</name>
<description>Minecraft dialog API intended for use with BungeeCord</description>
<licenses>
<license>
<name>BSD-3-Clause</name>
<url>https://github.com/SpigotMC/BungeeCord/blob/master/dialog/LICENSE</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -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 );
}
}

View File

@ -0,0 +1,9 @@
package net.md_5.bungee.api.dialog;
public interface Dialog
{
DialogBase getBase();
void setBase(DialogBase base);
}

View File

@ -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;
}

View File

@ -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<Dialog> dialogs;
@SerializedName("on_cancel")
private ClickEvent onCancel;
private int columns;
@SerializedName("button_width")
private int buttonWidth;
public DialogListDialog(DialogBase base, Dialog... dialogs)
{
this( base, Arrays.asList( dialogs ), null, 2, 150 );
}
public DialogListDialog(DialogBase base, List<Dialog> dialogs, ClickEvent onCancel, int columns, int buttonWidth)
{
this.base = base;
this.dialogs = dialogs;
this.onCancel = onCancel;
this.columns = columns;
this.buttonWidth = buttonWidth;
}
}

View File

@ -0,0 +1,42 @@
package net.md_5.bungee.api.dialog;
import com.google.common.base.Preconditions;
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;
import net.md_5.bungee.api.dialog.action.DialogClickAction;
@Data
@ToString
@EqualsAndHashCode
@Accessors(fluent = true)
public class MultiActionDialog implements Dialog
{
@Accessors(fluent = false)
private DialogBase base;
private List<DialogClickAction> actions;
private int columns;
@SerializedName("on_cancel")
private ClickEvent onCancel;
public MultiActionDialog(DialogBase base, DialogClickAction... actions)
{
this( base, Arrays.asList( actions ), 2, null );
}
public MultiActionDialog(DialogBase base, List<DialogClickAction> actions, int columns, ClickEvent onCancel)
{
Preconditions.checkArgument( actions != null && !actions.isEmpty(), "At least one action must be provided" );
this.base = base;
this.actions = actions;
this.columns = columns;
this.onCancel = onCancel;
}
}

View File

@ -0,0 +1,29 @@
package net.md_5.bungee.api.dialog;
import java.util.List;
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;
import net.md_5.bungee.api.dialog.input.DialogInput;
@Data
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@Accessors(fluent = true)
public class MultiActionInputFormDialog implements Dialog
{
@Accessors(fluent = false)
private DialogBase base;
private List<DialogInput> inputs;
private List<DialogClickAction> actions;
public MultiActionInputFormDialog(DialogBase base)
{
this( base, null, null );
}
}

View File

@ -0,0 +1,26 @@
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 NoticeDialog implements Dialog
{
@Accessors(fluent = false)
private DialogBase base;
private DialogClickAction action;
public NoticeDialog(DialogBase base)
{
this( base, null );
}
}

View File

@ -0,0 +1,31 @@
package net.md_5.bungee.api.dialog;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.ClickEvent;
@Data
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@Accessors(fluent = true)
public class ServerLinksDialog implements Dialog
{
@Accessors(fluent = false)
private DialogBase base;
@SerializedName("on_click")
private ClickEvent onClick;
private int columns;
@SerializedName("button_width")
private int buttonWidth;
public ServerLinksDialog(DialogBase base)
{
this( base, null, 2, 150 );
}
}

View File

@ -0,0 +1,40 @@
package net.md_5.bungee.api.dialog;
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.dialog.action.DialogSubmitAction;
import net.md_5.bungee.api.dialog.input.DialogInput;
@Data
@ToString
@EqualsAndHashCode
@Accessors(fluent = true)
public class SimpleInputFormDialog implements Dialog
{
@Accessors(fluent = false)
private DialogBase base;
private List<DialogInput> inputs;
private DialogSubmitAction action;
public SimpleInputFormDialog(DialogBase base, DialogInput... inputs)
{
this( base, null, inputs );
}
public SimpleInputFormDialog(DialogBase base, DialogSubmitAction action, DialogInput... inputs)
{
this( base, action, Arrays.asList( inputs ) );
}
public SimpleInputFormDialog(DialogBase base, DialogSubmitAction action, List<DialogInput> inputs)
{
this.base = base;
this.inputs = inputs;
this.action = action;
}
}

View File

@ -0,0 +1,20 @@
package net.md_5.bungee.api.dialog.action;
import lombok.AllArgsConstructor;
import lombok.Data;
import net.md_5.bungee.api.chat.BaseComponent;
@Data
@AllArgsConstructor
public class DialogAction
{
private BaseComponent label;
private BaseComponent tooltip;
private int width;
public DialogAction(BaseComponent label)
{
this( label, null, 150 );
}
}

View File

@ -0,0 +1,36 @@
package net.md_5.bungee.api.dialog.action;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class DialogClickAction extends DialogAction
{
@SerializedName("on_click")
private ClickEvent onClick;
public DialogClickAction(BaseComponent label)
{
this( null, label );
}
public DialogClickAction(ClickEvent onClick, BaseComponent label)
{
this( onClick, label, null, 150 );
}
public DialogClickAction(ClickEvent onClick, BaseComponent label, BaseComponent tooltip, int width)
{
super( label, tooltip, width );
this.onClick = onClick;
}
}

View File

@ -0,0 +1,33 @@
package net.md_5.bungee.api.dialog.action;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.dialog.submit.DialogSubmission;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class DialogSubmitAction extends DialogAction
{
private String id;
@SerializedName("on_submit")
private DialogSubmission onSubmit;
public DialogSubmitAction(String id, DialogSubmission onSubmit, BaseComponent label)
{
this( id, onSubmit, label, null, 150 );
}
public DialogSubmitAction(String id, DialogSubmission onSubmit, BaseComponent label, BaseComponent tooltip, int width)
{
super( label, tooltip, width );
this.id = id;
this.onSubmit = onSubmit;
}
}

View File

@ -0,0 +1,10 @@
package net.md_5.bungee.api.dialog.body;
import lombok.Data;
@Data
public class DialogBody
{
private final String type;
}

View File

@ -0,0 +1,28 @@
package net.md_5.bungee.api.dialog.body;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.chat.BaseComponent;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class PlainMessageBody extends DialogBody
{
private BaseComponent contents;
private int width;
public PlainMessageBody(BaseComponent contents)
{
this( contents, 200 );
}
public PlainMessageBody(BaseComponent contents, int width)
{
super( "minecraft:plain_message" );
this.contents = contents;
this.width = width;
}
}

View File

@ -0,0 +1,42 @@
package net.md_5.bungee.api.dialog.chat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.dialog.Dialog;
/**
* Click event which displays either a pre-existing dialog by key or a custom
* dialog.
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ShowDialogClickEvent extends ClickEvent
{
/**
* Key for a pre-existing dialog to show.
*/
private String reference;
/**
* Dialog to show.
*/
private Dialog dialog;
public ShowDialogClickEvent(String reference)
{
this( reference, null );
}
public ShowDialogClickEvent(Dialog dialog)
{
this( null, dialog );
}
private ShowDialogClickEvent(String reference, Dialog dialog)
{
super( Action.SHOW_DIALOG, null );
this.reference = reference;
this.dialog = dialog;
}
}

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.api.dialog.input;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.BaseComponent;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BooleanInput extends DialogInput
{
private BaseComponent label;
private boolean initial;
@SerializedName("on_true")
private String onTrue;
@SerializedName("on_false")
private String onFalse;
public BooleanInput(String key, BaseComponent label)
{
this( key, label, false, "true", "false" );
}
public BooleanInput(String key, BaseComponent label, boolean initial, String onTrue, String onFalse)
{
super( "minecraft:boolean", key );
this.label = label;
this.initial = initial;
this.onTrue = onTrue;
this.onFalse = onFalse;
}
}

View File

@ -0,0 +1,13 @@
package net.md_5.bungee.api.dialog.input;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
public class DialogInput
{
private final String type;
private final String key;
}

View File

@ -0,0 +1,22 @@
package net.md_5.bungee.api.dialog.input;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.BaseComponent;
@Data
@AllArgsConstructor
@Accessors(fluent = true)
public class InputOption
{
private String id;
private BaseComponent display;
private boolean initial;
public InputOption(String id)
{
this( id, null, false );
}
}

View File

@ -0,0 +1,40 @@
package net.md_5.bungee.api.dialog.input;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.BaseComponent;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class NumberRangeInput extends DialogInput
{
private int width;
private BaseComponent label;
private String labelFormat;
private int start;
private int end;
private int steps;
private int initial;
public NumberRangeInput(String key, BaseComponent label, int start, int end, int steps)
{
this( key, 200, label, "options.generic_value", start, end, steps, start );
}
public NumberRangeInput(String key, int width, BaseComponent label, String labelFormat, int start, int end, int steps, int initial)
{
super( "minecraft:number_range", key );
this.width = width;
this.label = label;
this.labelFormat = labelFormat;
this.start = start;
this.end = end;
this.steps = steps;
this.initial = initial;
}
}

View File

@ -0,0 +1,38 @@
package net.md_5.bungee.api.dialog.input;
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.BaseComponent;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class SingleOptionInput extends DialogInput
{
private int width;
private BaseComponent label;
@SerializedName("label_visible")
private boolean labelVisible;
private List<InputOption> options;
public SingleOptionInput(String key, BaseComponent label, InputOption... options)
{
this( key, 200, label, true, Arrays.asList( options ) );
}
public SingleOptionInput(String key, int width, BaseComponent label, boolean labelVisible, List<InputOption> options)
{
super( "minecraft:single_option", key );
this.width = width;
this.label = label;
this.labelVisible = labelVisible;
this.options = options;
}
}

View File

@ -0,0 +1,36 @@
package net.md_5.bungee.api.dialog.input;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import net.md_5.bungee.api.chat.BaseComponent;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class TextInput extends DialogInput
{
private int width;
private BaseComponent label;
@SerializedName("label_visible")
private boolean labelVisible;
private String initial;
public TextInput(String key, BaseComponent label)
{
this( key, 200, label, true, "" );
}
public TextInput(String key, int width, BaseComponent label, boolean labelVisible, String initial)
{
super( "minecraft:text", key );
this.width = width;
this.label = label;
this.labelVisible = labelVisible;
this.initial = initial;
}
}

View File

@ -0,0 +1,22 @@
package net.md_5.bungee.api.dialog.submit;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CommandTemplateSubmission extends DialogSubmission
{
private String template;
public CommandTemplateSubmission(String template)
{
super( "minecraft:command_template" );
this.template = template;
}
}

View File

@ -0,0 +1,22 @@
package net.md_5.bungee.api.dialog.submit;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CustomFormSubmission extends DialogSubmission
{
private String id;
public CustomFormSubmission(String id)
{
super( "minecraft:custom_form" );
this.id = id;
}
}

View File

@ -0,0 +1,24 @@
package net.md_5.bungee.api.dialog.submit;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CustomTemplateSubmission extends DialogSubmission
{
private String id;
private String template;
public CustomTemplateSubmission(String id, String template)
{
super( "minecraft:custom_template" );
this.id = id;
this.template = template;
}
}

View File

@ -0,0 +1,12 @@
package net.md_5.bungee.api.dialog.submit;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(fluent = true)
public class DialogSubmission
{
private final String type;
}

View File

@ -35,12 +35,14 @@
<module>bootstrap</module>
<module>chat</module>
<module>config</module>
<module>dialog</module>
<module>event</module>
<module>log</module>
<module>module</module>
<module>protocol</module>
<module>proxy</module>
<module>query</module>
<module>serializer</module>
<module>slf4j</module>
<module>native</module>
</modules>

View File

@ -36,7 +36,7 @@
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<artifactId>bungeecord-serializer</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>

View File

@ -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
{
}
}

View File

@ -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 )
);
}
},

View File

@ -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<String> SUPPORTED_VERSIONS;
public static final List<Integer> SUPPORTED_VERSION_IDS;

View File

@ -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 );
}
}

View File

@ -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 )
};
}

View File

@ -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 );
}
}

View File

@ -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<Integer, Dialog> 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 );
}
}

View File

@ -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 );
}
}

View File

@ -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 ) ) );
}
}

View File

@ -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<String, String> data = null;
if ( customClickAction.getData() != null )
{
ImmutableMap.Builder<String, String> 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()
{

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

41
serializer/pom.xml Normal file
View File

@ -0,0 +1,41 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.21-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-serializer</artifactId>
<version>1.21-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Serializer</name>
<description>Minecraft JSON serializer intended for use with BungeeCord</description>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>bungeecord-dialog</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -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;

View File

@ -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<BaseCompon
@Getter
@ApiStatus.Internal
private final ChatVersion version;
@Getter
@ApiStatus.Internal
private final DialogSerializer dialogSerializer;
public VersionedComponentSerializer(ChatVersion version)
{
this.version = version;
this.dialogSerializer = new DialogSerializer( this );
this.gson = new GsonBuilder().
registerTypeAdapter( BaseComponent.class, this ).
registerTypeAdapter( TextComponent.class, new TextComponentSerializer( this ) ).
@ -56,6 +64,9 @@ public class VersionedComponentSerializer implements JsonDeserializer<BaseCompon
registerTypeAdapter( Text.class, new TextSerializer() ).
registerTypeAdapter( Item.class, new ItemSerializer() ).
registerTypeAdapter( ItemTag.class, new ItemTag.Serializer() ).
// Dialogs
registerTypeAdapter( Dialog.class, dialogSerializer ).
registerTypeAdapter( ShowDialogClickEvent.class, new ShowDialogClickEventSerializer() ).
create();
}

View File

@ -0,0 +1,117 @@
package net.md_5.bungee.dialog;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.dialog.ConfirmationDialog;
import net.md_5.bungee.api.dialog.Dialog;
import net.md_5.bungee.api.dialog.DialogBase;
import net.md_5.bungee.api.dialog.DialogListDialog;
import net.md_5.bungee.api.dialog.MultiActionDialog;
import net.md_5.bungee.api.dialog.MultiActionInputFormDialog;
import net.md_5.bungee.api.dialog.NoticeDialog;
import net.md_5.bungee.api.dialog.ServerLinksDialog;
import net.md_5.bungee.api.dialog.SimpleInputFormDialog;
import net.md_5.bungee.chat.VersionedComponentSerializer;
@RequiredArgsConstructor
public class DialogSerializer implements JsonDeserializer<Dialog>, JsonSerializer<Dialog>
{
private static final BiMap<String, Class<? extends Dialog>> TYPES;
private final VersionedComponentSerializer serializer;
static
{
ImmutableBiMap.Builder<String, Class<? extends Dialog>> 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;
}
}

View File

@ -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<ShowDialogClickEvent>, JsonSerializer<ShowDialogClickEvent>
{
@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 );
}
}

View File

@ -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 );
}
}