Compare commits
53 Commits
f6151dce56
...
0e9e0b58d2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0e9e0b58d2 | ||
![]() |
8cb49bc10a | ||
![]() |
5b05934fe8 | ||
![]() |
97f65726d2 | ||
![]() |
e3ab8ef15f | ||
![]() |
d5bcabdc60 | ||
![]() |
3cd530f007 | ||
![]() |
2b9808cd13 | ||
![]() |
70fa02f3a4 | ||
![]() |
4ebc3c96b2 | ||
![]() |
dd1531e28d | ||
![]() |
5709a65785 | ||
![]() |
5348aad094 | ||
![]() |
b60c1bdb37 | ||
![]() |
93508d5083 | ||
![]() |
1f159f8eaa | ||
![]() |
31f7ef8c54 | ||
![]() |
244412405a | ||
![]() |
9cd0d3289f | ||
![]() |
7cde213e63 | ||
![]() |
aa44ebe770 | ||
![]() |
5dad41034b | ||
![]() |
cd1ceb4c31 | ||
![]() |
23ba5141f1 | ||
![]() |
415ac8c81e | ||
![]() |
41e49dad6b | ||
![]() |
bec329352d | ||
![]() |
89e66ed648 | ||
![]() |
d8f9d81b30 | ||
![]() |
363003d8c7 | ||
![]() |
a696bb0e9f | ||
![]() |
68f4f6bd40 | ||
![]() |
442ff808f3 | ||
![]() |
fbbcc454d5 | ||
![]() |
f8de305477 | ||
![]() |
f1f5be18f9 | ||
![]() |
e05560976b | ||
![]() |
8bff00f15b | ||
![]() |
4d37c2488e | ||
![]() |
75456b2c0a | ||
![]() |
53365e4b18 | ||
![]() |
69e4872f40 | ||
![]() |
a336efb8fa | ||
![]() |
ae2fc30b7b | ||
![]() |
2bafb70581 | ||
![]() |
617c2728a2 | ||
![]() |
89069a362d | ||
![]() |
1279cca971 | ||
![]() |
26433bf021 | ||
![]() |
d81040cd6f | ||
![]() |
d7538df91b | ||
![]() |
2516de6586 | ||
![]() |
1da3a8c240 |
4
.github/workflows/maven.yml
vendored
4
.github/workflows/maven.yml
vendored
@ -4,12 +4,12 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
java: [8, 11, 17, 21]
|
||||
java: [8, 11, 17, 21, 25-ea]
|
||||
|
||||
name: Java ${{ matrix.java }}
|
||||
|
||||
|
10
api/pom.xml
10
api/pom.xml
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-API</name>
|
||||
@ -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>
|
||||
|
@ -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;
|
||||
@ -382,4 +383,31 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
void transfer(String host, int port);
|
||||
|
||||
/**
|
||||
* Gets the client brand of this player.
|
||||
* If the player has not sent a brand packet yet, it will return null.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
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;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Called after a {@link ProxiedPlayer} runs a custom action from a chat event
|
||||
* or form submission.
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = false)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@ApiStatus.Experimental
|
||||
public class CustomClickEvent extends Event implements Cancellable
|
||||
{
|
||||
|
||||
/**
|
||||
* Player who clicked.
|
||||
*/
|
||||
private final ProxiedPlayer player;
|
||||
/**
|
||||
* Custom action ID.
|
||||
*/
|
||||
private final String id;
|
||||
/**
|
||||
* The data as submitted.
|
||||
*/
|
||||
private final JsonElement data;
|
||||
/**
|
||||
* Cancelled state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
}
|
@ -35,6 +35,7 @@ import org.eclipse.aether.transport.http.HttpTransporterFactory;
|
||||
class LibraryLoader
|
||||
{
|
||||
|
||||
private static final String REPOSITORY_PROPERTY = "net.md_5.bungee.api.plugin.centralURL";
|
||||
private final Logger logger;
|
||||
private final RepositorySystem repository;
|
||||
private final DefaultRepositorySystemSession session;
|
||||
@ -68,7 +69,7 @@ class LibraryLoader
|
||||
session.setSystemProperties( System.getProperties() );
|
||||
session.setReadOnly();
|
||||
|
||||
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) );
|
||||
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", System.getProperty( REPOSITORY_PROPERTY, "https://repo.maven.apache.org/maven2" ) ).build() ) );
|
||||
}
|
||||
|
||||
public ClassLoader createLoader(PluginDescription desc)
|
||||
|
@ -1,22 +1,37 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import gnu.trove.strategy.HashingStrategy;
|
||||
import it.unimi.dsi.fastutil.Hash;
|
||||
import java.util.Locale;
|
||||
|
||||
class CaseInsensitiveHashingStrategy implements HashingStrategy
|
||||
class CaseInsensitiveHashingStrategy implements Hash.Strategy<String>
|
||||
{
|
||||
|
||||
static final CaseInsensitiveHashingStrategy INSTANCE = new CaseInsensitiveHashingStrategy();
|
||||
|
||||
@Override
|
||||
public int computeHashCode(Object object)
|
||||
public int hashCode(String object)
|
||||
{
|
||||
return ( (String) object ).toLowerCase( Locale.ROOT ).hashCode();
|
||||
if ( object == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return object.toLowerCase( Locale.ROOT ).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o1, Object o2)
|
||||
public boolean equals(String o1, String o2)
|
||||
{
|
||||
return o1.equals( o2 ) || ( o1 instanceof String && o2 instanceof String && ( (String) o1 ).toLowerCase( Locale.ROOT ).equals( ( (String) o2 ).toLowerCase( Locale.ROOT ) ) );
|
||||
if ( o1 == o2 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( o1 == null || o2 == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return o1.equals( o2 ) || o1.toLowerCase( Locale.ROOT ).equals( o2.toLowerCase( Locale.ROOT ) );
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import gnu.trove.map.hash.TCustomHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V>
|
||||
public class CaseInsensitiveMap<V> extends Object2ObjectOpenCustomHashMap<String, V>
|
||||
{
|
||||
|
||||
public CaseInsensitiveMap()
|
||||
@ -13,6 +13,6 @@ public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V>
|
||||
|
||||
public CaseInsensitiveMap(Map<? extends String, ? extends V> map)
|
||||
{
|
||||
super( CaseInsensitiveHashingStrategy.INSTANCE, map );
|
||||
super( map, CaseInsensitiveHashingStrategy.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import gnu.trove.set.hash.TCustomHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CaseInsensitiveSet extends TCustomHashSet<String>
|
||||
public class CaseInsensitiveSet extends ObjectOpenCustomHashSet<String>
|
||||
{
|
||||
|
||||
public CaseInsensitiveSet()
|
||||
@ -13,6 +13,6 @@ public class CaseInsensitiveSet extends TCustomHashSet<String>
|
||||
|
||||
public CaseInsensitiveSet(Collection<? extends String> collection)
|
||||
{
|
||||
super( CaseInsensitiveHashingStrategy.INSTANCE, collection );
|
||||
super( collection, CaseInsensitiveHashingStrategy.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,12 @@ public class CaseInsensitiveTest
|
||||
CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>();
|
||||
|
||||
map.put( "FOO", obj );
|
||||
assertTrue( map.contains( "foo" ) ); // Assert that contains is case insensitive
|
||||
assertTrue( map.containsKey( "foo" ) ); // Assert that contains is case insensitive
|
||||
assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved
|
||||
|
||||
// Assert that remove is case insensitive
|
||||
map.remove( "FoO" );
|
||||
assertFalse( map.contains( "foo" ) );
|
||||
assertFalse( map.containsKey( "foo" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-bootstrap</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Bootstrap</name>
|
||||
@ -48,6 +48,7 @@
|
||||
<Main-Class>net.md_5.bungee.Bootstrap</Main-Class>
|
||||
<Implementation-Version>${describe}</Implementation-Version>
|
||||
<Specification-Version>${maven.build.timestamp}</Specification-Version>
|
||||
<Enable-Native-Access>ALL-UNNAMED</Enable-Native-Access>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Chat</name>
|
||||
|
@ -4,6 +4,7 @@ import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -677,11 +678,11 @@ public abstract class BaseComponent
|
||||
public String toPlainText()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
toPlainText( builder );
|
||||
toPlainText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) );
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
void toPlainText(StringBuilder builder)
|
||||
void toPlainText(StringVisitor builder)
|
||||
{
|
||||
if ( extra != null )
|
||||
{
|
||||
@ -701,11 +702,11 @@ public abstract class BaseComponent
|
||||
public String toLegacyText()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
toLegacyText( builder );
|
||||
toLegacyText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) );
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
void toLegacyText(StringBuilder builder)
|
||||
void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
if ( extra != null )
|
||||
{
|
||||
@ -716,7 +717,7 @@ public abstract class BaseComponent
|
||||
}
|
||||
}
|
||||
|
||||
void addFormat(StringBuilder builder)
|
||||
void addFormat(StringVisitor builder)
|
||||
{
|
||||
builder.append( getColor() );
|
||||
if ( isBold() )
|
||||
@ -740,4 +741,35 @@ public abstract class BaseComponent
|
||||
builder.append( ChatColor.MAGIC );
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
protected static interface StringVisitor
|
||||
{
|
||||
|
||||
void append(String s);
|
||||
|
||||
default void append(Object obj)
|
||||
{
|
||||
append( String.valueOf( obj ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
protected static class LimitedStringVisitor implements StringVisitor
|
||||
{
|
||||
|
||||
private final StringBuilder builder;
|
||||
private final int maxLength;
|
||||
|
||||
@Override
|
||||
public void append(String s)
|
||||
{
|
||||
if ( builder.length() >= maxLength )
|
||||
{
|
||||
throw new IllegalArgumentException( "String exceeded maximum length " + maxLength );
|
||||
}
|
||||
|
||||
builder.append( s );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -50,14 +50,14 @@ public final class KeybindComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( getKeybind() );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( getKeybind() );
|
||||
|
@ -85,14 +85,14 @@ public final class ScoreComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( this.value );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( this.value );
|
||||
|
@ -69,14 +69,14 @@ public final class SelectorComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( this.selector );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( this.selector );
|
||||
|
@ -280,14 +280,14 @@ public final class TextComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( text );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( text );
|
||||
|
@ -156,20 +156,20 @@ public final class TranslatableComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
convert( builder, false );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
convert( builder, true );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
||||
private void convert(StringBuilder builder, boolean applyFormat)
|
||||
private void convert(StringVisitor builder, boolean applyFormat)
|
||||
{
|
||||
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
||||
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-config</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Config</name>
|
||||
|
28
dialog/LICENSE
Normal file
28
dialog/LICENSE
Normal 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.
|
38
dialog/README.md
Normal file
38
dialog/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
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 NoticeDialog(
|
||||
new DialogBase( new ComponentBuilder( "Hello" ).color( ChatColor.RED ).build() )
|
||||
.inputs(
|
||||
Arrays.asList( new TextInput( "first", new ComponentBuilder( "First" ).build() ),
|
||||
new TextInput( "second", new ComponentBuilder( "Second" ).build() )
|
||||
)
|
||||
) )
|
||||
.action( new ActionButton( new ComponentBuilder( "Submit Button" ).build(), new CustomClickAction( "customform" ) ) );
|
||||
|
||||
player.sendMessage( new ComponentBuilder( "click me" ).event( new ShowDialogClickEvent( notice ) ).build() );
|
||||
}
|
||||
}
|
||||
```
|
31
dialog/nb-configuration.xml
Normal file
31
dialog/nb-configuration.xml
Normal 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
36
dialog/pom.xml
Normal 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.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-dialog</artifactId>
|
||||
<version>1.21-R0.4-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>
|
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.api.dialog;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
||||
|
||||
/**
|
||||
* Represents a simple dialog with text and two actions at the bottom (default:
|
||||
* "yes", "no").
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public final class ConfirmationDialog implements Dialog
|
||||
{
|
||||
|
||||
@NonNull
|
||||
@Accessors(fluent = false)
|
||||
private DialogBase base;
|
||||
/**
|
||||
* The "yes" click action / bottom (appears on the left).
|
||||
*/
|
||||
private ActionButton yes;
|
||||
/**
|
||||
* The "no" click action / bottom (appears on the right).
|
||||
*/
|
||||
private ActionButton no;
|
||||
|
||||
public ConfirmationDialog(@NonNull DialogBase base)
|
||||
{
|
||||
this( base, null, null );
|
||||
}
|
||||
}
|
29
dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java
Normal file
29
dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java
Normal file
@ -0,0 +1,29 @@
|
||||
package net.md_5.bungee.api.dialog;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents a dialog GUI.
|
||||
*/
|
||||
public interface Dialog
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets the dialog base which contains the dialog title and other options
|
||||
* common to all types of dialogs.
|
||||
*
|
||||
* @return mutable reference to the dialog base
|
||||
*/
|
||||
DialogBase getBase();
|
||||
|
||||
/**
|
||||
* Sets the dialog base.
|
||||
* <br>
|
||||
* For internal use only as this is mandatory and should be specified in the
|
||||
* constructor.
|
||||
*
|
||||
* @param base the new dialog base
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
void setBase(DialogBase base);
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package net.md_5.bungee.api.dialog;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.dialog.body.DialogBody;
|
||||
import net.md_5.bungee.api.dialog.input.DialogInput;
|
||||
|
||||
/**
|
||||
* Represents the title and other options common to all dialogs.
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public final class DialogBase
|
||||
{
|
||||
|
||||
/**
|
||||
* The mandatory dialog title.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent title;
|
||||
/**
|
||||
* The name which is used for any buttons leading to this dialog (eg from a
|
||||
* {@link DialogListDialog}). Otherwise defaults to {@link #title}.
|
||||
*/
|
||||
@SerializedName("external_title")
|
||||
private BaseComponent externalTitle;
|
||||
/**
|
||||
* The inputs to the dialog.
|
||||
*/
|
||||
private List<DialogInput> inputs;
|
||||
/**
|
||||
* The body elements which make up this dialog.
|
||||
*/
|
||||
private List<DialogBody> body;
|
||||
/**
|
||||
* Whether this dialog can be closed with the escape key (default: true).
|
||||
*/
|
||||
@SerializedName("can_close_with_escape")
|
||||
private Boolean canCloseWithEscape;
|
||||
/**
|
||||
* Whether this dialog should pause the game in single-player mode (default:
|
||||
* true).
|
||||
*/
|
||||
private Boolean pause;
|
||||
/**
|
||||
* Action to take after the a click or submit action is performed on the
|
||||
* dialog (default: close).
|
||||
*/
|
||||
@SerializedName("after_action")
|
||||
private AfterAction afterAction;
|
||||
|
||||
public DialogBase(@NonNull BaseComponent title)
|
||||
{
|
||||
this( title, null, null, null, null, null, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of action which may be taken after the dialog.
|
||||
*/
|
||||
public enum AfterAction
|
||||
{
|
||||
/**
|
||||
* Close the dialog.
|
||||
*/
|
||||
@SerializedName("close")
|
||||
CLOSE,
|
||||
/**
|
||||
* Do nothing.
|
||||
*/
|
||||
@SerializedName("none")
|
||||
NONE,
|
||||
/**
|
||||
* Show a waiting for response screen.
|
||||
*/
|
||||
@SerializedName("wait_for_response")
|
||||
WAIT_FOR_RESPONSE;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
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.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
||||
|
||||
/**
|
||||
* Represents a dialog which contains buttons that link to other dialogs.
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@Accessors(fluent = true)
|
||||
public final class DialogListDialog implements Dialog
|
||||
{
|
||||
|
||||
@NonNull
|
||||
@Accessors(fluent = false)
|
||||
private DialogBase base;
|
||||
/**
|
||||
* The child dialogs behind each button.
|
||||
*/
|
||||
private List<Dialog> dialogs;
|
||||
/**
|
||||
* The {@link ActionButton} activated when the dialog is exited.
|
||||
*/
|
||||
@SerializedName("exit_action")
|
||||
private ActionButton exitAction;
|
||||
/**
|
||||
* The number of columns for the dialog buttons (default: 2).
|
||||
*/
|
||||
private Integer columns;
|
||||
/**
|
||||
* The width of the dialog buttons (default: 150, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
@SerializedName("button_width")
|
||||
private Integer buttonWidth;
|
||||
|
||||
public DialogListDialog(@NonNull DialogBase base, Dialog... dialogs)
|
||||
{
|
||||
this( base, Arrays.asList( dialogs ), null, null, null );
|
||||
}
|
||||
|
||||
public DialogListDialog(@NonNull DialogBase base, List<Dialog> dialogs, ActionButton exitAction, Integer columns, Integer buttonWidth)
|
||||
{
|
||||
this.base = base;
|
||||
this.dialogs = dialogs;
|
||||
this.exitAction = exitAction;
|
||||
columns( columns );
|
||||
buttonWidth( buttonWidth );
|
||||
}
|
||||
|
||||
public DialogListDialog columns(Integer columns)
|
||||
{
|
||||
Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" );
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DialogListDialog buttonWidth(Integer buttonWidth)
|
||||
{
|
||||
Preconditions.checkArgument( buttonWidth == null || ( buttonWidth >= 1 && buttonWidth <= 1024 ), "buttonWidth must be between 1 and 1024" );
|
||||
this.buttonWidth = buttonWidth;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
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.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
||||
|
||||
/**
|
||||
* Represents a dialog with text a list of action buttons grouped into columns
|
||||
* and scrollable if necessary.
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@Accessors(fluent = true)
|
||||
public final class MultiActionDialog implements Dialog
|
||||
{
|
||||
|
||||
@NonNull
|
||||
@Accessors(fluent = false)
|
||||
private DialogBase base;
|
||||
/**
|
||||
* The action buttons in the dialog. At least one must be provided.
|
||||
*/
|
||||
@NonNull
|
||||
private List<ActionButton> actions;
|
||||
/**
|
||||
* The number of columns for the dialog buttons (default: 2).
|
||||
*/
|
||||
private Integer columns;
|
||||
/**
|
||||
* The {@link ActionButton} activated when the dialog is exited.
|
||||
*/
|
||||
@SerializedName("exit_action")
|
||||
private ActionButton exitAction;
|
||||
|
||||
public MultiActionDialog(@NonNull DialogBase base, @NonNull ActionButton... actions)
|
||||
{
|
||||
this( base, Arrays.asList( actions ), null, null );
|
||||
}
|
||||
|
||||
public MultiActionDialog(@NonNull DialogBase base, @NonNull List<ActionButton> actions, Integer columns, ActionButton exitAction)
|
||||
{
|
||||
Preconditions.checkArgument( !actions.isEmpty(), "At least one action must be provided" );
|
||||
|
||||
this.base = base;
|
||||
this.actions = actions;
|
||||
columns( columns );
|
||||
this.exitAction = exitAction;
|
||||
}
|
||||
|
||||
public MultiActionDialog columns(Integer columns)
|
||||
{
|
||||
Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" );
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.md_5.bungee.api.dialog;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
||||
|
||||
/**
|
||||
* Represents a simple dialog with text and one action at the bottom (default:
|
||||
* "OK").
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@AllArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public final class NoticeDialog implements Dialog
|
||||
{
|
||||
|
||||
@NonNull
|
||||
@Accessors(fluent = false)
|
||||
private DialogBase base;
|
||||
/**
|
||||
* The "OK" action button for the dialog.
|
||||
*/
|
||||
private ActionButton action;
|
||||
|
||||
public NoticeDialog(DialogBase base)
|
||||
{
|
||||
this( base, null );
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package net.md_5.bungee.api.dialog;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
||||
|
||||
/**
|
||||
* Represents a dialog which shows the links configured/sent from the server.
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@Accessors(fluent = true)
|
||||
public final class ServerLinksDialog implements Dialog
|
||||
{
|
||||
|
||||
@NonNull
|
||||
@Accessors(fluent = false)
|
||||
private DialogBase base;
|
||||
/**
|
||||
* The optional {@link ActionButton} for this dialog.
|
||||
*/
|
||||
@SerializedName("action")
|
||||
private ActionButton action;
|
||||
/**
|
||||
* The {@link ActionButton} activated when the dialog is exited.
|
||||
*/
|
||||
@SerializedName("exit_action")
|
||||
private ActionButton exitAction;
|
||||
/**
|
||||
* The number of columns for the dialog buttons (default: 2).
|
||||
*/
|
||||
private Integer columns;
|
||||
/**
|
||||
* The width of the dialog buttons (default: 150, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
@SerializedName("button_width")
|
||||
private Integer buttonWidth;
|
||||
|
||||
public ServerLinksDialog(@NonNull DialogBase base)
|
||||
{
|
||||
this( base, null, null, null );
|
||||
}
|
||||
|
||||
public ServerLinksDialog(@NonNull DialogBase base, ActionButton action, Integer columns, Integer buttonWidth)
|
||||
{
|
||||
this.base = base;
|
||||
this.action = action;
|
||||
columns( columns );
|
||||
buttonWidth( buttonWidth );
|
||||
}
|
||||
|
||||
public ServerLinksDialog columns(Integer columns)
|
||||
{
|
||||
Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" );
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerLinksDialog buttonWidth(Integer buttonWidth)
|
||||
{
|
||||
Preconditions.checkArgument( buttonWidth == null || ( buttonWidth >= 1 && buttonWidth <= 1024 ), "buttonWidth must be between 1 and 1024" );
|
||||
this.buttonWidth = buttonWidth;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
public interface Action
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a dialog action which will usually appear as a button.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
public class ActionButton
|
||||
{
|
||||
|
||||
/**
|
||||
* The text label of the button, mandatory.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* The hover tooltip of the button.
|
||||
*/
|
||||
private BaseComponent tooltip;
|
||||
/**
|
||||
* The width of the button (default: 150, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The action to take.
|
||||
*/
|
||||
@NonNull
|
||||
private Action action;
|
||||
|
||||
public ActionButton(@NonNull BaseComponent label, BaseComponent tooltip, Integer width, @NonNull Action action)
|
||||
{
|
||||
this.label = label;
|
||||
this.tooltip = tooltip;
|
||||
setWidth( width );
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public ActionButton(@NonNull BaseComponent label, @NonNull Action action)
|
||||
{
|
||||
this( label, null, null, action );
|
||||
}
|
||||
|
||||
public void setWidth(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* Submits the dialog with the given ID and values as a payload.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
public class CustomClickAction implements Action
|
||||
{
|
||||
|
||||
/**
|
||||
* The namespaced key of the submission.
|
||||
*/
|
||||
@NonNull
|
||||
private String id;
|
||||
/**
|
||||
* Fields to be added to the submission payload.
|
||||
*/
|
||||
private JsonElement additions;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* Executes a command. If the command requires a permission
|
||||
* higher than 0, a confirmation dialog will be shown by the client.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RunCommandAction implements Action
|
||||
{
|
||||
|
||||
/**
|
||||
* The template to be applied, where variables of the form
|
||||
* <code>$(key)</code> will be replaced by their
|
||||
* {@link net.md_5.bungee.api.dialog.input.DialogInput#key} value.
|
||||
*/
|
||||
@NonNull
|
||||
private String template;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
|
||||
/**
|
||||
* Represents a static dialog action.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
public class StaticAction implements Action
|
||||
{
|
||||
|
||||
@NonNull
|
||||
private ClickEvent clickEvent;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains the different actions/buttons for a {@link net.md_5.bungee.api.dialog.Dialog}.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.action;
|
@ -0,0 +1,20 @@
|
||||
package net.md_5.bungee.api.dialog.body;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents the body content of a {@link net.md_5.bungee.api.dialog.Dialog}.
|
||||
*/
|
||||
@Data
|
||||
public abstract class DialogBody
|
||||
{
|
||||
|
||||
/**
|
||||
* The internal body type.
|
||||
*/
|
||||
@NonNull
|
||||
@ApiStatus.Internal
|
||||
private final String type;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package net.md_5.bungee.api.dialog.body;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a dialog body which consists of text constrained to a certain
|
||||
* width.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PlainMessageBody extends DialogBody
|
||||
{
|
||||
|
||||
/**
|
||||
* The text body.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent contents;
|
||||
/**
|
||||
* The maximum width (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
|
||||
public PlainMessageBody(@NonNull BaseComponent contents)
|
||||
{
|
||||
this( contents, null );
|
||||
}
|
||||
|
||||
public PlainMessageBody(@NonNull BaseComponent contents, Integer width)
|
||||
{
|
||||
super( "minecraft:plain_message" );
|
||||
this.contents = contents;
|
||||
width( width );
|
||||
}
|
||||
|
||||
public void width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Contains the different {@link net.md_5.bungee.api.dialog.Dialog} body content
|
||||
* types.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.body;
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains dialog extensions to the chat API.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.chat;
|
@ -0,0 +1,54 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a checkbox input control.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BooleanInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The input label.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* The initial value (default: false/unchecked).
|
||||
*/
|
||||
private Boolean initial;
|
||||
/**
|
||||
* The string value to be submitted when true/checked (default: "true").
|
||||
*/
|
||||
@SerializedName("on_true")
|
||||
private String onTrue;
|
||||
/**
|
||||
* The string value to be submitted when false/unchecked (default: "false").
|
||||
*/
|
||||
@SerializedName("on_false")
|
||||
private String onFalse;
|
||||
|
||||
public BooleanInput(@NonNull String key, @NonNull BaseComponent label)
|
||||
{
|
||||
this( key, label, null, "true", "false" );
|
||||
}
|
||||
|
||||
public BooleanInput(@NonNull String key, @NonNull BaseComponent label, Boolean initial, String onTrue, String onFalse)
|
||||
{
|
||||
super( "minecraft:boolean", key );
|
||||
this.label = label;
|
||||
this.initial = initial;
|
||||
this.onTrue = onTrue;
|
||||
this.onFalse = onFalse;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents a type of input which may be displayed/submitted with a form
|
||||
* dialog.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
public class DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The internal input type.
|
||||
*/
|
||||
@NonNull
|
||||
@ApiStatus.Internal
|
||||
private final String type;
|
||||
/**
|
||||
* The key corresponding to this input and associated with the value
|
||||
* submitted.
|
||||
*/
|
||||
@NonNull
|
||||
private final String key;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents an option choice which may form part of a
|
||||
* {@link SingleOptionInput}.
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public class InputOption
|
||||
{
|
||||
|
||||
/**
|
||||
* The string value associated with this option, to be submitted when
|
||||
* selected.
|
||||
*/
|
||||
@NonNull
|
||||
private String id;
|
||||
/**
|
||||
* The text to display for this option.
|
||||
*/
|
||||
private BaseComponent display;
|
||||
/**
|
||||
* Whether this option is the one initially selected. Only one option may
|
||||
* have this value as true (default: first option).
|
||||
*/
|
||||
private Boolean initial;
|
||||
|
||||
public InputOption(@NonNull String id)
|
||||
{
|
||||
this( id, null, null );
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a number slider input.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NumberRangeInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The width of the input (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The label of the slider.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* A translate key used to display the label value (default:
|
||||
* options.generic_value).
|
||||
*/
|
||||
private String labelFormat;
|
||||
/**
|
||||
* The start position of the slider (leftmost position).
|
||||
*/
|
||||
private float start;
|
||||
/**
|
||||
* The end position of the slider (rightmost position).
|
||||
*/
|
||||
private float end;
|
||||
/**
|
||||
* The steps in which the input will be increased or decreased, or null if
|
||||
* no specific steps.
|
||||
*/
|
||||
private Float step;
|
||||
/**
|
||||
* The initial value of number input, or null to fall back to the middle.
|
||||
*/
|
||||
private Float initial;
|
||||
|
||||
public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end)
|
||||
{
|
||||
this( key, null, label, "options.generic_value", start, end, null, null );
|
||||
}
|
||||
|
||||
public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end, Float step)
|
||||
{
|
||||
this( key, null, label, "options.generic_value", start, end, step, null );
|
||||
}
|
||||
|
||||
public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end, Float step, Float initial)
|
||||
{
|
||||
this( key, null, label, "options.generic_value", start, end, step, initial );
|
||||
}
|
||||
|
||||
public NumberRangeInput(@NonNull String key, Integer width, @NonNull BaseComponent label, String labelFormat, float start, float end, Float step, Float initial)
|
||||
{
|
||||
super( "minecraft:number_range", key );
|
||||
width( width );
|
||||
this.label = label;
|
||||
this.labelFormat = labelFormat;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
step( step );
|
||||
initial( initial );
|
||||
}
|
||||
|
||||
public NumberRangeInput width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "with must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NumberRangeInput step(Float step)
|
||||
{
|
||||
Preconditions.checkArgument( step == null || step > 0, "step must be null or greater than zero" );
|
||||
this.step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NumberRangeInput initial(Float initial)
|
||||
{
|
||||
// we need to calculate if the initial value is between start and end, regardless of the order
|
||||
float min = Math.min( start, end );
|
||||
float max = Math.max( start, end );
|
||||
Preconditions.checkArgument( initial == null || ( initial >= min && initial <= max ), "initial must be null or between start and end" );
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
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.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a single option (dropdown) input.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SingleOptionInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The width of the input (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The input label.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* Whether the label is visible (default: true).
|
||||
*/
|
||||
@SerializedName("label_visible")
|
||||
private Boolean labelVisible;
|
||||
/**
|
||||
* The non-empty list of options to be selected from.
|
||||
*/
|
||||
@NonNull
|
||||
private List<InputOption> options;
|
||||
|
||||
public SingleOptionInput(@NonNull String key, @NonNull BaseComponent label, @NonNull InputOption... options)
|
||||
{
|
||||
this( key, null, label, null, Arrays.asList( options ) );
|
||||
}
|
||||
|
||||
public SingleOptionInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, @NonNull List<InputOption> options)
|
||||
{
|
||||
super( "minecraft:single_option", key );
|
||||
Preconditions.checkArgument( !options.isEmpty(), "At least one option must be provided" );
|
||||
|
||||
width( width );
|
||||
this.label = label;
|
||||
this.labelVisible = labelVisible;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public SingleOptionInput width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a textbox input.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TextInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The width of this text input (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The label of this text input.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* The visibility of this text input's label.
|
||||
*/
|
||||
@SerializedName("label_visible")
|
||||
private Boolean labelVisible;
|
||||
/**
|
||||
* The initial value of this text input.
|
||||
*/
|
||||
private String initial;
|
||||
/**
|
||||
* The maximum length of the input (default: 32).
|
||||
*/
|
||||
@SerializedName("max_length")
|
||||
private Integer maxLength;
|
||||
/**
|
||||
* If present, allows users to input multiple lines.
|
||||
*/
|
||||
private Multiline multiline;
|
||||
|
||||
public TextInput(@NonNull String key, @NonNull BaseComponent label)
|
||||
{
|
||||
this( key, null, label, null, null, null, null );
|
||||
}
|
||||
|
||||
public TextInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, String initial, Integer maxLength)
|
||||
{
|
||||
this( key, width, label, labelVisible, initial, maxLength, null );
|
||||
}
|
||||
|
||||
public TextInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, String initial, Integer maxLength, Multiline multiline)
|
||||
{
|
||||
super( "minecraft:text", key );
|
||||
width( width );
|
||||
this.label = label;
|
||||
this.labelVisible = labelVisible;
|
||||
this.initial = initial;
|
||||
this.maxLength = maxLength;
|
||||
this.multiline = multiline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration data for a multiline input.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public static class Multiline
|
||||
{
|
||||
|
||||
/**
|
||||
* The maximum length of input, or null to disable any limits.
|
||||
*/
|
||||
@SerializedName("max_lines")
|
||||
private Integer maxLines;
|
||||
/**
|
||||
* The height of this input (default: 32, minimum: 1, maximum: 512).
|
||||
*/
|
||||
private Integer height;
|
||||
|
||||
public Multiline(Integer maxLines, Integer height)
|
||||
{
|
||||
height( height ).maxLines( maxLines );
|
||||
}
|
||||
|
||||
public Multiline height(Integer height)
|
||||
{
|
||||
Preconditions.checkArgument( height == null || height >= 1 && height <= 512, "height must null or be between 1 and 512" );
|
||||
this.height = height;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public TextInput width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Represents the various input controls which may be present on form dialogs.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.input;
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains the core classes for the display of a {@link net.md_5.bungee.api.dialog.Dialog}.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog;
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Event</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-log</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Log</name>
|
||||
@ -20,9 +20,9 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12.1</version>
|
||||
<version>3.30.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -1,26 +1,18 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import jline.console.ConsoleReader;
|
||||
import org.jline.reader.LineReader;
|
||||
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private final LogDispatcher dispatcher = new LogDispatcher( this );
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
@SuppressWarnings(
|
||||
{
|
||||
"CallToPrintStackTrace", "CallToThreadStartDuringObjectConstruction"
|
||||
})
|
||||
// CHECKSTYLE:ON
|
||||
@SuppressFBWarnings("SC_START_IN_CTOR")
|
||||
public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader)
|
||||
public BungeeLogger(String loggerName, String filePattern, LineReader reader)
|
||||
{
|
||||
super( loggerName, null );
|
||||
setLevel( Level.ALL );
|
||||
|
@ -1,15 +1,15 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.regex.Pattern;
|
||||
import jline.console.ConsoleReader;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.fusesource.jansi.Ansi.Erase;
|
||||
import org.jline.jansi.Ansi;
|
||||
import org.jline.reader.LineReader;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ColouredWriter extends Handler
|
||||
{
|
||||
|
||||
@ -52,12 +52,7 @@ public class ColouredWriter extends Handler
|
||||
compile( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() ),
|
||||
};
|
||||
//
|
||||
private final ConsoleReader console;
|
||||
|
||||
public ColouredWriter(ConsoleReader console)
|
||||
{
|
||||
this.console = console;
|
||||
}
|
||||
private final LineReader console;
|
||||
|
||||
public void print(String s)
|
||||
{
|
||||
@ -65,14 +60,7 @@ public class ColouredWriter extends Handler
|
||||
{
|
||||
s = replacement.pattern.matcher( s ).replaceAll( replacement.replacement );
|
||||
}
|
||||
try
|
||||
{
|
||||
console.print( Ansi.ansi().eraseLine( Erase.ALL ).toString() + ConsoleReader.RESET_LINE + s + Ansi.ansi().reset().toString() );
|
||||
console.drawLine();
|
||||
console.flush();
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
}
|
||||
console.printAbove( s + Ansi.ansi().reset().toString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,7 +18,6 @@ public class ConciseFormatter extends Formatter
|
||||
private final boolean coloured;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ThrowableResultIgnored")
|
||||
public String format(LogRecord record)
|
||||
{
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-alert</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_alert</name>
|
||||
|
@ -15,7 +15,7 @@ public class CommandAlertRaw extends Command
|
||||
|
||||
public CommandAlertRaw()
|
||||
{
|
||||
super( "alertraw", "bungeecord.command.alert" );
|
||||
super( "alertraw", "bungeecord.command.alertraw" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-find</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_find</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-kick</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_kick</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-list</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_list</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-send</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_send</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-server</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_server</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>BungeeCord Modules</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>reconnect_yaml</name>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-native</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Native</name>
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.md_5.bungee.jni;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -93,7 +95,31 @@ public final class NativeCode<T>
|
||||
return loaded;
|
||||
}
|
||||
|
||||
public static boolean hasDirectBuffers()
|
||||
{
|
||||
ByteBuf directBuffer = null;
|
||||
boolean hasMemoryAddress = false;
|
||||
try
|
||||
{
|
||||
directBuffer = Unpooled.directBuffer();
|
||||
hasMemoryAddress = directBuffer.hasMemoryAddress();
|
||||
} finally
|
||||
{
|
||||
if ( directBuffer != null )
|
||||
{
|
||||
directBuffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
return hasMemoryAddress;
|
||||
}
|
||||
|
||||
public static boolean isSupported()
|
||||
{
|
||||
return isSupportedPlatformAndArch() && hasDirectBuffers();
|
||||
}
|
||||
|
||||
private static boolean isSupportedPlatformAndArch()
|
||||
{
|
||||
return "Linux".equals( System.getProperty( "os.name" ) ) && ( isAmd64() || isAarch64() );
|
||||
}
|
||||
|
28
nbt/LICENSE
Normal file
28
nbt/LICENSE
Normal 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.
|
4
nbt/README.md
Normal file
4
nbt/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
BungeeCord-NBT
|
||||
=================
|
||||
|
||||
Minimal implementation of NBT for use in BungeeCord
|
31
nbt/nb-configuration.xml
Normal file
31
nbt/nb-configuration.xml
Normal 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>
|
27
nbt/pom.xml
Normal file
27
nbt/pom.xml
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
<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.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-nbt</artifactId>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-NBT</name>
|
||||
<description>Minimal implementation of NBT for use in BungeeCord</description>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>BSD-3-Clause</name>
|
||||
<url>https://github.com/SpigotMC/BungeeCord/blob/master/nbt/LICENSE</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
</project>
|
52
nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java
Normal file
52
nbt/src/main/java/net/md_5/bungee/nbt/NamedTag.java
Normal file
@ -0,0 +1,52 @@
|
||||
package net.md_5.bungee.nbt;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
import net.md_5.bungee.nbt.type.CompoundTag;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class NamedTag implements Tag
|
||||
{
|
||||
|
||||
private String name;
|
||||
private TypedTag tag;
|
||||
|
||||
/**
|
||||
* Reads the data of the {@link DataInput} and parses it into this
|
||||
* {@link NamedTag}.
|
||||
*
|
||||
* @param input input to read from
|
||||
* @param limiter limitation of the read data
|
||||
*/
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
byte type = input.readByte();
|
||||
name = CompoundTag.readString( input, limiter );
|
||||
tag = Tag.readById( type, input, limiter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this {@link NamedTag} into a {@link DataOutput}.
|
||||
*
|
||||
* @param output the output to write to
|
||||
*/
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( name, "name cannot be null" );
|
||||
Preconditions.checkNotNull( tag, "tag cannot be null" );
|
||||
|
||||
output.writeByte( tag.getId() );
|
||||
CompoundTag.writeString( name, output );
|
||||
tag.write( output );
|
||||
}
|
||||
}
|
167
nbt/src/main/java/net/md_5/bungee/nbt/Tag.java
Normal file
167
nbt/src/main/java/net/md_5/bungee/nbt/Tag.java
Normal file
@ -0,0 +1,167 @@
|
||||
package net.md_5.bungee.nbt;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Supplier;
|
||||
import net.md_5.bungee.nbt.exception.NBTFormatException;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
import net.md_5.bungee.nbt.type.ByteArrayTag;
|
||||
import net.md_5.bungee.nbt.type.ByteTag;
|
||||
import net.md_5.bungee.nbt.type.CompoundTag;
|
||||
import net.md_5.bungee.nbt.type.DoubleTag;
|
||||
import net.md_5.bungee.nbt.type.EndTag;
|
||||
import net.md_5.bungee.nbt.type.FloatTag;
|
||||
import net.md_5.bungee.nbt.type.IntArrayTag;
|
||||
import net.md_5.bungee.nbt.type.IntTag;
|
||||
import net.md_5.bungee.nbt.type.ListTag;
|
||||
import net.md_5.bungee.nbt.type.LongArrayTag;
|
||||
import net.md_5.bungee.nbt.type.LongTag;
|
||||
import net.md_5.bungee.nbt.type.ShortTag;
|
||||
import net.md_5.bungee.nbt.type.StringTag;
|
||||
|
||||
public interface Tag
|
||||
{
|
||||
|
||||
int OBJECT_HEADER = 8;
|
||||
int ARRAY_HEADER = 12;
|
||||
int STRING_SIZE = 28;
|
||||
int OBJECT_REFERENCE = 4;
|
||||
|
||||
Supplier<? extends TypedTag>[] CONSTRUCTORS = new Supplier[]
|
||||
{
|
||||
EndTag::new,
|
||||
ByteTag::new,
|
||||
ShortTag::new,
|
||||
IntTag::new,
|
||||
LongTag::new,
|
||||
FloatTag::new,
|
||||
DoubleTag::new,
|
||||
ByteArrayTag::new,
|
||||
StringTag::new,
|
||||
ListTag::new,
|
||||
CompoundTag::new,
|
||||
IntArrayTag::new,
|
||||
LongArrayTag::new
|
||||
};
|
||||
|
||||
byte END = 0;
|
||||
byte BYTE = 1;
|
||||
byte SHORT = 2;
|
||||
byte INT = 3;
|
||||
byte LONG = 4;
|
||||
byte FLOAT = 5;
|
||||
byte DOUBLE = 6;
|
||||
byte BYTE_ARRAY = 7;
|
||||
byte STRING = 8;
|
||||
byte LIST = 9;
|
||||
byte COMPOUND = 10;
|
||||
byte INT_ARRAY = 11;
|
||||
byte LONG_ARRAY = 12;
|
||||
|
||||
/**
|
||||
* Reads the data into this tag.
|
||||
*
|
||||
* @param input the input to read from
|
||||
* @param limiter the limiter for this read operation
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
void read(DataInput input, NBTLimiter limiter) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes this tag into a {@link DataOutput}.
|
||||
*
|
||||
* @param output the output to write to
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
void write(DataOutput output) throws IOException;
|
||||
|
||||
/**
|
||||
* Reads a {@link Tag} from the given {@link DataInput},
|
||||
* based on the specified tag type, with limitations of the
|
||||
* {@link NBTLimiter}.
|
||||
*
|
||||
* @param id the nbt type
|
||||
* @param input the input to read from
|
||||
* @param limiter the limiter for this read operation
|
||||
* @return the deserialized {@link Tag}
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
static TypedTag readById(byte id, DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
if ( id < END || id > LONG_ARRAY )
|
||||
{
|
||||
throw new NBTFormatException( "Invalid tag id: " + id );
|
||||
}
|
||||
|
||||
TypedTag tag = CONSTRUCTORS[id].get();
|
||||
tag.read( input, limiter );
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@link NamedTag} from the given {@link DataInput},
|
||||
* with limitations of the {@link NBTLimiter}.
|
||||
*
|
||||
* @param input the data input to read from
|
||||
* @param limiter the limiter for this read operation
|
||||
* @return the deserialized {@link NamedTag}
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
static NamedTag readNamedTag(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
NamedTag namedTag = new NamedTag();
|
||||
namedTag.read( input, limiter );
|
||||
return namedTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the given {@link TypedTag} into a byte array.
|
||||
* This is the inverse operation of {@link #fromByteArray(byte[])}.
|
||||
*
|
||||
* @param tag the tag to convert
|
||||
* @return the serialized byte array
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
static byte[] toByteArray(TypedTag tag) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
DataOutputStream dataOutputStream = new DataOutputStream( byteArrayOutputStream );
|
||||
dataOutputStream.writeByte( tag.getId() );
|
||||
tag.write( dataOutputStream );
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the given byte array into a {@link TypedTag}.
|
||||
* This is the inverse operation of {@link #toByteArray(TypedTag)}.
|
||||
*
|
||||
* @param data the byte array to read from
|
||||
* @return the deserialized {@link TypedTag}
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
static TypedTag fromByteArray(byte[] data) throws IOException
|
||||
{
|
||||
return fromByteArray( data, NBTLimiter.unlimitedSize() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the given byte array into a {@link TypedTag},
|
||||
* with limitations of the {@link NBTLimiter}.
|
||||
*
|
||||
* @param data the byte array to read from
|
||||
* @param limiter the limiter for this read operation
|
||||
* @return the deserialized {@link TypedTag}
|
||||
* @throws IOException if an exception occurs during io operations
|
||||
*/
|
||||
static TypedTag fromByteArray(byte[] data, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
DataInputStream stream = new DataInputStream( new ByteArrayInputStream( data ) );
|
||||
byte type = stream.readByte();
|
||||
return readById( type, stream, limiter );
|
||||
}
|
||||
}
|
12
nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java
Normal file
12
nbt/src/main/java/net/md_5/bungee/nbt/TypedTag.java
Normal file
@ -0,0 +1,12 @@
|
||||
package net.md_5.bungee.nbt;
|
||||
|
||||
public interface TypedTag extends Tag
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets the id of this tag's type.
|
||||
*
|
||||
* @return the id related to this tag's type
|
||||
*/
|
||||
byte getId();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.md_5.bungee.nbt.exception;
|
||||
|
||||
public class NBTException extends RuntimeException
|
||||
{
|
||||
|
||||
public NBTException(String message)
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.md_5.bungee.nbt.exception;
|
||||
|
||||
public class NBTFormatException extends NBTException
|
||||
{
|
||||
|
||||
public NBTFormatException(String message)
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package net.md_5.bungee.nbt.exception;
|
||||
|
||||
public class NBTLimitException extends NBTException
|
||||
{
|
||||
|
||||
public NBTLimitException(String message)
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
}
|
66
nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java
Normal file
66
nbt/src/main/java/net/md_5/bungee/nbt/limit/NBTLimiter.java
Normal file
@ -0,0 +1,66 @@
|
||||
package net.md_5.bungee.nbt.limit;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.nbt.exception.NBTLimitException;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class NBTLimiter
|
||||
{
|
||||
|
||||
private static final int MAX_STACK_DEPTH = 512;
|
||||
//
|
||||
private final long maxBytes;
|
||||
private final int maxDepth;
|
||||
|
||||
public static NBTLimiter unlimitedSize()
|
||||
{
|
||||
return new NBTLimiter( Long.MAX_VALUE, MAX_STACK_DEPTH );
|
||||
}
|
||||
|
||||
public NBTLimiter(long maxBytes)
|
||||
{
|
||||
this( maxBytes, MAX_STACK_DEPTH );
|
||||
}
|
||||
|
||||
private long usedBytes;
|
||||
private int depth;
|
||||
|
||||
public void countBytes(long amount)
|
||||
{
|
||||
if ( amount < 0 )
|
||||
{
|
||||
throw new NBTLimitException( "NBT limiter tried to count negative byte amount" );
|
||||
}
|
||||
|
||||
if ( ( usedBytes = Math.addExact( usedBytes, amount ) ) > maxBytes )
|
||||
{
|
||||
throw new NBTLimitException( "NBT tag is to big, bytes > " + maxBytes );
|
||||
}
|
||||
}
|
||||
|
||||
public void countBytes(long amount, long factor)
|
||||
{
|
||||
if ( amount < 0 || factor < 0 )
|
||||
{
|
||||
throw new NBTLimitException( "NBT limiter tried to count negative byte amount" );
|
||||
}
|
||||
|
||||
countBytes( Math.multiplyExact( amount, factor ) );
|
||||
}
|
||||
|
||||
public void push()
|
||||
{
|
||||
if ( ( depth = Math.addExact( depth, 1 ) ) > maxDepth )
|
||||
{
|
||||
throw new NBTLimitException( "NBT tag is to complex, depth > " + maxDepth );
|
||||
}
|
||||
}
|
||||
|
||||
public void pop()
|
||||
{
|
||||
if ( --depth < 0 )
|
||||
{
|
||||
throw new NBTLimitException( "NBT limiter tried to pop depth 0" );
|
||||
}
|
||||
}
|
||||
}
|
44
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java
Normal file
44
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteArrayTag.java
Normal file
@ -0,0 +1,44 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ByteArrayTag implements TypedTag
|
||||
{
|
||||
|
||||
private byte[] value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + ARRAY_HEADER + Integer.BYTES );
|
||||
int length = input.readInt();
|
||||
limiter.countBytes( length, Byte.BYTES );
|
||||
input.readFully( value = new byte[ length ] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( value, "byte array value cannot be null" );
|
||||
output.writeInt( value.length );
|
||||
output.write( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.BYTE_ARRAY;
|
||||
}
|
||||
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ByteTag.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ByteTag implements TypedTag
|
||||
{
|
||||
|
||||
private byte value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + Byte.BYTES );
|
||||
value = input.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
output.write( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.BYTE;
|
||||
}
|
||||
}
|
99
nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java
Normal file
99
nbt/src/main/java/net/md_5/bungee/nbt/type/CompoundTag.java
Normal file
@ -0,0 +1,99 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.exception.NBTFormatException;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CompoundTag implements TypedTag
|
||||
{
|
||||
|
||||
private static final int MAP_SIZE_IN_BYTES = 48;
|
||||
private static final int MAP_ENTRY_SIZE_IN_BYTES = 32;
|
||||
//
|
||||
private Map<String, TypedTag> value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.push();
|
||||
limiter.countBytes( MAP_SIZE_IN_BYTES );
|
||||
Map<String, TypedTag> map = new LinkedHashMap<>();
|
||||
for ( byte type; ( type = input.readByte() ) != Tag.END; )
|
||||
{
|
||||
String name = readString( input, limiter );
|
||||
TypedTag tag = Tag.readById( type, input, limiter );
|
||||
if ( map.put( name, tag ) == null )
|
||||
{
|
||||
limiter.countBytes( MAP_ENTRY_SIZE_IN_BYTES + OBJECT_REFERENCE );
|
||||
}
|
||||
}
|
||||
limiter.pop();
|
||||
value = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( value, "compound tag map cannot be null" );
|
||||
for ( Map.Entry<String, TypedTag> entry : value.entrySet() )
|
||||
{
|
||||
String name = entry.getKey();
|
||||
TypedTag tag = entry.getValue();
|
||||
output.writeByte( tag.getId() );
|
||||
if ( tag.getId() == Tag.END )
|
||||
{
|
||||
throw new NBTFormatException( "invalid end tag in compound tag" );
|
||||
}
|
||||
writeString( name, output );
|
||||
tag.write( output );
|
||||
}
|
||||
output.writeByte( 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.COMPOUND;
|
||||
}
|
||||
|
||||
public static String readString(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( STRING_SIZE );
|
||||
String string = input.readUTF();
|
||||
limiter.countBytes( string.length(), Character.BYTES );
|
||||
return string;
|
||||
}
|
||||
|
||||
public static void writeString(String string, DataOutput output) throws IOException
|
||||
{
|
||||
output.writeUTF( string );
|
||||
}
|
||||
|
||||
public TypedTag get(String key)
|
||||
{
|
||||
return value.get( key );
|
||||
}
|
||||
|
||||
public void put(String key, TypedTag tag)
|
||||
{
|
||||
value.put( key, tag );
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return value.size();
|
||||
}
|
||||
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/DoubleTag.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DoubleTag implements TypedTag
|
||||
{
|
||||
|
||||
private double value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + Double.BYTES );
|
||||
value = input.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
output.writeDouble( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.DOUBLE;
|
||||
}
|
||||
}
|
34
nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java
Normal file
34
nbt/src/main/java/net/md_5/bungee/nbt/type/EndTag.java
Normal file
@ -0,0 +1,34 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class EndTag implements TypedTag
|
||||
{
|
||||
|
||||
public static final EndTag INSTANCE = new EndTag();
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter)
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.END;
|
||||
}
|
||||
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/FloatTag.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class FloatTag implements TypedTag
|
||||
{
|
||||
|
||||
private float value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + Float.BYTES );
|
||||
value = input.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
output.writeFloat( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.FLOAT;
|
||||
}
|
||||
}
|
52
nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java
Normal file
52
nbt/src/main/java/net/md_5/bungee/nbt/type/IntArrayTag.java
Normal file
@ -0,0 +1,52 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IntArrayTag implements TypedTag
|
||||
{
|
||||
|
||||
private int[] value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + ARRAY_HEADER + Integer.BYTES );
|
||||
int length = input.readInt();
|
||||
limiter.countBytes( length, Integer.BYTES );
|
||||
int[] data = new int[ length ];
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
data[i] = input.readInt();
|
||||
}
|
||||
value = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( value, "int array value cannot be null" );
|
||||
output.writeInt( value.length );
|
||||
for ( int i : value )
|
||||
{
|
||||
output.writeInt( i );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.INT_ARRAY;
|
||||
}
|
||||
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/IntTag.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IntTag implements TypedTag
|
||||
{
|
||||
|
||||
private int value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + Integer.BYTES );
|
||||
value = input.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
output.writeInt( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.INT;
|
||||
}
|
||||
}
|
92
nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java
Normal file
92
nbt/src/main/java/net/md_5/bungee/nbt/type/ListTag.java
Normal file
@ -0,0 +1,92 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.exception.NBTFormatException;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ListTag implements TypedTag
|
||||
{
|
||||
|
||||
public static final int LIST_HEADER = 12;
|
||||
//
|
||||
private List<TypedTag> value;
|
||||
private byte listType;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.push();
|
||||
limiter.countBytes( OBJECT_HEADER + LIST_HEADER + ARRAY_HEADER + Byte.BYTES + Integer.BYTES );
|
||||
listType = input.readByte();
|
||||
int length = input.readInt();
|
||||
|
||||
if ( length < 0 )
|
||||
{
|
||||
throw new NBTFormatException( "ListTag length cannot be negative" );
|
||||
}
|
||||
|
||||
if ( listType == Tag.END && length > 0 )
|
||||
{
|
||||
throw new NBTFormatException( "Missing type in ListTag" );
|
||||
}
|
||||
|
||||
limiter.countBytes( length, OBJECT_REFERENCE );
|
||||
List<TypedTag> tagList = new ArrayList<>( length );
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
tagList.add( Tag.readById( listType, input, limiter ) );
|
||||
}
|
||||
limiter.pop();
|
||||
|
||||
value = tagList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( value, "list value cannot be null" );
|
||||
if ( listType == Tag.END && !value.isEmpty() )
|
||||
{
|
||||
throw new NBTFormatException( "Missing type in ListTag" );
|
||||
}
|
||||
output.writeByte( listType );
|
||||
output.writeInt( value.size() );
|
||||
for ( TypedTag tag : value )
|
||||
{
|
||||
if ( tag.getId() != listType )
|
||||
{
|
||||
throw new NBTFormatException( "ListTag type mismatch" );
|
||||
}
|
||||
tag.write( output );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.LIST;
|
||||
}
|
||||
|
||||
public TypedTag get(int index)
|
||||
{
|
||||
return value.get( index );
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return value.size();
|
||||
}
|
||||
}
|
53
nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java
Normal file
53
nbt/src/main/java/net/md_5/bungee/nbt/type/LongArrayTag.java
Normal file
@ -0,0 +1,53 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LongArrayTag implements TypedTag
|
||||
{
|
||||
|
||||
private long[] value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + ARRAY_HEADER + Integer.BYTES );
|
||||
int length = input.readInt();
|
||||
limiter.countBytes( length, Long.BYTES );
|
||||
long[] data = new long[ length ];
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
data[i] = input.readLong();
|
||||
}
|
||||
value = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( value, "long array value cannot be null" );
|
||||
|
||||
output.writeInt( value.length );
|
||||
for ( long i : value )
|
||||
{
|
||||
output.writeLong( i );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.LONG_ARRAY;
|
||||
}
|
||||
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/LongTag.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LongTag implements TypedTag
|
||||
{
|
||||
|
||||
private long value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + Long.BYTES );
|
||||
value = input.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
output.writeLong( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.LONG;
|
||||
}
|
||||
}
|
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java
Normal file
39
nbt/src/main/java/net/md_5/bungee/nbt/type/ShortTag.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ShortTag implements TypedTag
|
||||
{
|
||||
|
||||
private short value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + Short.BYTES );
|
||||
value = input.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
output.writeShort( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.SHORT;
|
||||
}
|
||||
}
|
44
nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java
Normal file
44
nbt/src/main/java/net/md_5/bungee/nbt/type/StringTag.java
Normal file
@ -0,0 +1,44 @@
|
||||
package net.md_5.bungee.nbt.type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class StringTag implements TypedTag
|
||||
{
|
||||
|
||||
private String value;
|
||||
|
||||
@Override
|
||||
public void read(DataInput input, NBTLimiter limiter) throws IOException
|
||||
{
|
||||
limiter.countBytes( OBJECT_HEADER + STRING_SIZE );
|
||||
String string = input.readUTF();
|
||||
limiter.countBytes( string.length(), Character.BYTES );
|
||||
value = string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException
|
||||
{
|
||||
Preconditions.checkNotNull( value, "string value cannot be null" );
|
||||
|
||||
output.writeUTF( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getId()
|
||||
{
|
||||
return Tag.STRING;
|
||||
}
|
||||
}
|
53
nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java
Normal file
53
nbt/src/test/java/net/md_5/bungee/nbt/NBTLimiterTest.java
Normal file
@ -0,0 +1,53 @@
|
||||
package net.md_5.bungee.nbt;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.ArrayList;
|
||||
import net.md_5.bungee.nbt.exception.NBTLimitException;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
import net.md_5.bungee.nbt.type.ByteArrayTag;
|
||||
import net.md_5.bungee.nbt.type.ListTag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class NBTLimiterTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testNbtLimiter()
|
||||
{
|
||||
assertThrows( NBTLimitException.class, () ->
|
||||
{
|
||||
ByteArrayTag byteArrayTag = new ByteArrayTag( new byte[ 1000 ] );
|
||||
byte[] arr = Tag.toByteArray( byteArrayTag );
|
||||
Tag.fromByteArray( arr, new NBTLimiter( 100, 1 ) );
|
||||
} );
|
||||
|
||||
assertDoesNotThrow( () ->
|
||||
{
|
||||
ByteArrayTag byteArrayTag = new ByteArrayTag( new byte[ 1000 ] );
|
||||
byte[] arr = Tag.toByteArray( byteArrayTag );
|
||||
Tag.fromByteArray( arr, new NBTLimiter( 99999999, 1 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDepth()
|
||||
{
|
||||
assertThrows( NBTLimitException.class, () ->
|
||||
{
|
||||
ListTag root = new ListTag( new ArrayList<>(), Tag.LIST );
|
||||
root.getValue().add( new ListTag( new ArrayList<>(), Tag.LIST ) );
|
||||
|
||||
byte[] arr = Tag.toByteArray( root );
|
||||
Tag.fromByteArray( arr, new NBTLimiter( 100, 1 ) );
|
||||
} );
|
||||
|
||||
assertDoesNotThrow( () ->
|
||||
{
|
||||
ListTag root = new ListTag( new ArrayList<>(), Tag.LIST );
|
||||
root.getValue().add( new ListTag( new ArrayList<>(), Tag.LIST ) );
|
||||
|
||||
byte[] arr = Tag.toByteArray( root );
|
||||
Tag.fromByteArray( arr, new NBTLimiter( 100, 2 ) );
|
||||
} );
|
||||
}
|
||||
}
|
247
nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java
Normal file
247
nbt/src/test/java/net/md_5/bungee/nbt/NBTTagTest.java
Normal file
@ -0,0 +1,247 @@
|
||||
package net.md_5.bungee.nbt;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.md_5.bungee.nbt.exception.NBTFormatException;
|
||||
import net.md_5.bungee.nbt.type.ByteArrayTag;
|
||||
import net.md_5.bungee.nbt.type.ByteTag;
|
||||
import net.md_5.bungee.nbt.type.CompoundTag;
|
||||
import net.md_5.bungee.nbt.type.DoubleTag;
|
||||
import net.md_5.bungee.nbt.type.EndTag;
|
||||
import net.md_5.bungee.nbt.type.FloatTag;
|
||||
import net.md_5.bungee.nbt.type.IntArrayTag;
|
||||
import net.md_5.bungee.nbt.type.IntTag;
|
||||
import net.md_5.bungee.nbt.type.ListTag;
|
||||
import net.md_5.bungee.nbt.type.LongArrayTag;
|
||||
import net.md_5.bungee.nbt.type.LongTag;
|
||||
import net.md_5.bungee.nbt.type.ShortTag;
|
||||
import net.md_5.bungee.nbt.type.StringTag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class NBTTagTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testByteTag() throws IOException
|
||||
{
|
||||
byte[] tests = new byte[]
|
||||
{
|
||||
0, Byte.MAX_VALUE, Byte.MIN_VALUE
|
||||
};
|
||||
for ( byte value : tests )
|
||||
{
|
||||
ByteTag byteTag = new ByteTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( byteTag );
|
||||
ByteTag reSerialized = (ByteTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( byteTag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortTag() throws IOException
|
||||
{
|
||||
short[] tests = new short[]
|
||||
{
|
||||
0, Short.MAX_VALUE, Short.MIN_VALUE
|
||||
};
|
||||
for ( short value : tests )
|
||||
{
|
||||
ShortTag tag = new ShortTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
ShortTag reSerialized = (ShortTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntTag() throws IOException
|
||||
{
|
||||
int[] tests = new int[]
|
||||
{
|
||||
0, Integer.MAX_VALUE, Integer.MIN_VALUE
|
||||
};
|
||||
for ( int value : tests )
|
||||
{
|
||||
IntTag tag = new IntTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
IntTag reSerialized = (IntTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongTag() throws IOException
|
||||
{
|
||||
long[] tests = new long[]
|
||||
{
|
||||
0, Long.MAX_VALUE, Long.MIN_VALUE
|
||||
};
|
||||
for ( long value : tests )
|
||||
{
|
||||
LongTag tag = new LongTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
LongTag reSerialized = (LongTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleTag() throws IOException
|
||||
{
|
||||
double[] tests = new double[]
|
||||
{
|
||||
0, Double.MAX_VALUE, Double.MIN_VALUE, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY
|
||||
};
|
||||
for ( double value : tests )
|
||||
{
|
||||
DoubleTag tag = new DoubleTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
DoubleTag reSerialized = (DoubleTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatTag() throws IOException
|
||||
{
|
||||
float[] tests = new float[]
|
||||
{
|
||||
0, Float.MAX_VALUE, Float.MIN_VALUE, Float.NaN, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY
|
||||
};
|
||||
for ( float value : tests )
|
||||
{
|
||||
FloatTag tag = new FloatTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
FloatTag reSerialized = (FloatTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringTag() throws IOException
|
||||
{
|
||||
String[] tests = new String[]
|
||||
{
|
||||
"Outfluencer", "", String.valueOf( System.currentTimeMillis() ), "BungeeCord", new Object().toString()
|
||||
};
|
||||
for ( String value : tests )
|
||||
{
|
||||
StringTag tag = new StringTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
StringTag reSerialized = (StringTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByteArrayTag() throws IOException
|
||||
{
|
||||
byte[] value = new byte[ 1024 ];
|
||||
ThreadLocalRandom.current().nextBytes( value );
|
||||
ByteArrayTag tag = new ByteArrayTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
ByteArrayTag reSerialized = (ByteArrayTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
|
||||
value = new byte[ 0 ];
|
||||
ThreadLocalRandom.current().nextBytes( value );
|
||||
tag = new ByteArrayTag( value );
|
||||
deserialized = Tag.toByteArray( tag );
|
||||
reSerialized = (ByteArrayTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntArrayTag() throws IOException
|
||||
{
|
||||
int[] value = new int[ 1024 ];
|
||||
for ( int i = 0; i < value.length; i++ )
|
||||
{
|
||||
value[i] = ThreadLocalRandom.current().nextInt();
|
||||
}
|
||||
IntArrayTag tag = new IntArrayTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
IntArrayTag reSerialized = (IntArrayTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
|
||||
value = new int[ 0 ];
|
||||
tag = new IntArrayTag( value );
|
||||
deserialized = Tag.toByteArray( tag );
|
||||
reSerialized = (IntArrayTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongArrayTag() throws IOException
|
||||
{
|
||||
long[] value = new long[ 1024 ];
|
||||
for ( int i = 0; i < value.length; i++ )
|
||||
{
|
||||
value[i] = ThreadLocalRandom.current().nextLong();
|
||||
}
|
||||
LongArrayTag tag = new LongArrayTag( value );
|
||||
byte[] deserialized = Tag.toByteArray( tag );
|
||||
LongArrayTag reSerialized = (LongArrayTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
|
||||
value = new long[ 0 ];
|
||||
tag = new LongArrayTag( value );
|
||||
deserialized = Tag.toByteArray( tag );
|
||||
reSerialized = (LongArrayTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( tag, reSerialized );
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListTag() throws IOException
|
||||
{
|
||||
List<TypedTag> tags = new ArrayList<>();
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
tags.add( new IntTag( i ) );
|
||||
}
|
||||
ListTag listTag = new ListTag( tags, Tag.INT );
|
||||
byte[] deserialized = Tag.toByteArray( listTag );
|
||||
ListTag reSerialized = (ListTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( reSerialized.getValue(), tags );
|
||||
List<TypedTag> tags2 = new ArrayList<>();
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
tags2.add( new IntTag( i ) );
|
||||
}
|
||||
tags2.add( new ByteTag( Byte.MIN_VALUE ) );
|
||||
assertThrows( NBTFormatException.class, () -> Tag.toByteArray( new ListTag( tags2, Tag.INT ) ) );
|
||||
assertThrows( NBTFormatException.class, () -> Tag.toByteArray( new ListTag( Collections.singletonList( new EndTag() ), Tag.END ) ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompoundTag() throws IOException
|
||||
{
|
||||
Map<String, TypedTag> map = new HashMap<>();
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
map.put( "" + i, new IntTag( i ) );
|
||||
map.put( "a" + i, new ByteTag( (byte) i ) );
|
||||
map.put( "b" + i, new ShortTag( (short) i ) );
|
||||
map.put( "c" + i, new LongTag( i ) );
|
||||
map.put( "f" + i, new FloatTag( i ) );
|
||||
map.put( "d" + i, new DoubleTag( i ) );
|
||||
}
|
||||
CompoundTag compoundTag = new CompoundTag( map );
|
||||
byte[] deserialized = Tag.toByteArray( compoundTag );
|
||||
CompoundTag reSerialized = (CompoundTag) Tag.fromByteArray( deserialized );
|
||||
assertEquals( reSerialized, compoundTag );
|
||||
Map<String, TypedTag> map2 = new LinkedHashMap<>();
|
||||
map2.put( "", new EndTag() );
|
||||
CompoundTag compoundTag2 = new CompoundTag( map2 );
|
||||
assertThrows( NBTFormatException.class, () -> Tag.toByteArray( compoundTag2 ) );
|
||||
}
|
||||
}
|
29
nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java
Normal file
29
nbt/src/test/java/net/md_5/bungee/nbt/PlayerDataTest.java
Normal file
@ -0,0 +1,29 @@
|
||||
package net.md_5.bungee.nbt;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Objects;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
import net.md_5.bungee.nbt.type.CompoundTag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class PlayerDataTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testPlayerData() throws URISyntaxException, IOException
|
||||
{
|
||||
ClassLoader classLoader = PlayerDataTest.class.getClassLoader();
|
||||
File file = new File( Objects.requireNonNull( classLoader.getResource( "playerdata.nbt" ) ).toURI() );
|
||||
FileInputStream fileInputStream = new FileInputStream( file );
|
||||
DataInputStream dis = new DataInputStream( fileInputStream );
|
||||
NamedTag namedTag = Tag.readNamedTag( dis, NBTLimiter.unlimitedSize() );
|
||||
assertInstanceOf( CompoundTag.class, namedTag.getTag() );
|
||||
assertEquals( namedTag.getName(), "" );
|
||||
}
|
||||
}
|
BIN
nbt/src/test/resources/playerdata.nbt
Normal file
BIN
nbt/src/test/resources/playerdata.nbt
Normal file
Binary file not shown.
19
pom.xml
19
pom.xml
@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>BungeeCord-Parent</name>
|
||||
@ -35,14 +35,17 @@
|
||||
<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>
|
||||
<module>nbt</module>
|
||||
</modules>
|
||||
|
||||
<scm>
|
||||
@ -72,7 +75,7 @@
|
||||
|
||||
<properties>
|
||||
<build.number>unknown</build.number>
|
||||
<lombok.version>1.18.36</lombok.version>
|
||||
<lombok.version>1.18.38</lombok.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@ -83,7 +86,7 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-bom</artifactId>
|
||||
<version>4.1.119.Final</version>
|
||||
<version>4.2.1.Final</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@ -99,15 +102,9 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.3.1-jre</version>
|
||||
<version>33.4.8-jre</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>findbugs-annotations</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations-java5</artifactId>
|
||||
@ -182,7 +179,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
<version>1.23</version>
|
||||
<version>1.24</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-classes</phase>
|
||||
|
@ -6,13 +6,13 @@
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>1.21-R0.3-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Protocol</name>
|
||||
@ -36,7 +36,13 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<artifactId>bungeecord-serializer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-nbt</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@ -46,15 +52,9 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.trove4j</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>se.llbit</groupId>
|
||||
<artifactId>jo-nbt</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil-core</artifactId>
|
||||
<version>8.5.15</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import net.md_5.bungee.protocol.packet.BossBar;
|
||||
import net.md_5.bungee.protocol.packet.BundleDelimiter;
|
||||
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 +12,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 +44,8 @@ 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.ShowDialogDirect;
|
||||
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 +283,24 @@ public abstract class AbstractPacketHandler
|
||||
public void handle(ServerLinks serverLinks) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(ShowDialog showDialog) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(ShowDialogDirect showDialogDirect) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(ClearDialog clearDialog) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(CustomClickAction customClickAction) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(BundleDelimiter bundleDelimiter) throws Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,11 @@ import java.util.function.BiConsumer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ComponentStyle;
|
||||
import se.llbit.nbt.ErrorTag;
|
||||
import se.llbit.nbt.NamedTag;
|
||||
import se.llbit.nbt.SpecificTag;
|
||||
import se.llbit.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.NamedTag;
|
||||
import net.md_5.bungee.nbt.Tag;
|
||||
import net.md_5.bungee.nbt.TypedTag;
|
||||
import net.md_5.bungee.nbt.limit.NBTLimiter;
|
||||
import net.md_5.bungee.nbt.type.EndTag;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class DefinedPacket
|
||||
@ -116,7 +117,7 @@ public abstract class DefinedPacket
|
||||
{
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
||||
{
|
||||
SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
|
||||
TypedTag nbt = (TypedTag) readTag( buf, protocolVersion );
|
||||
JsonElement json = TagUtil.toJson( nbt );
|
||||
|
||||
return ChatSerializer.forVersion( protocolVersion ).deserialize( json );
|
||||
@ -130,7 +131,7 @@ public abstract class DefinedPacket
|
||||
|
||||
public static ComponentStyle readComponentStyle(ByteBuf buf, int protocolVersion)
|
||||
{
|
||||
SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion );
|
||||
TypedTag nbt = (TypedTag) readTag( buf, protocolVersion );
|
||||
JsonElement json = TagUtil.toJson( nbt );
|
||||
|
||||
return ChatSerializer.forVersion( protocolVersion ).deserializeStyle( json );
|
||||
@ -152,8 +153,7 @@ public abstract class DefinedPacket
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3 )
|
||||
{
|
||||
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( message );
|
||||
SpecificTag nbt = TagUtil.fromJson( json );
|
||||
|
||||
TypedTag nbt = TagUtil.fromJson( json );
|
||||
writeTag( nbt, buf, protocolVersion );
|
||||
} else
|
||||
{
|
||||
@ -166,8 +166,7 @@ public abstract class DefinedPacket
|
||||
public static void writeComponentStyle(ComponentStyle style, ByteBuf buf, int protocolVersion)
|
||||
{
|
||||
JsonElement json = ChatSerializer.forVersion( protocolVersion ).toJson( style );
|
||||
SpecificTag nbt = TagUtil.fromJson( json );
|
||||
|
||||
TypedTag nbt = TagUtil.fromJson( json );
|
||||
writeTag( nbt, buf, protocolVersion );
|
||||
}
|
||||
|
||||
@ -455,30 +454,32 @@ public abstract class DefinedPacket
|
||||
|
||||
public static Tag readTag(ByteBuf input, int protocolVersion)
|
||||
{
|
||||
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
|
||||
Tag tag;
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
|
||||
return readTag( input, protocolVersion, new NBTLimiter( 1 << 21 ) );
|
||||
}
|
||||
|
||||
public static Tag readTag(ByteBuf input, int protocolVersion, NBTLimiter limiter)
|
||||
{
|
||||
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
|
||||
try
|
||||
{
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
|
||||
{
|
||||
byte type = in.readByte();
|
||||
if ( type == 0 )
|
||||
{
|
||||
return Tag.END;
|
||||
return EndTag.INSTANCE;
|
||||
} else
|
||||
{
|
||||
tag = SpecificTag.read( type, in );
|
||||
return Tag.readById( type, in, limiter );
|
||||
}
|
||||
}
|
||||
NamedTag namedTag = new NamedTag();
|
||||
namedTag.read( in, limiter );
|
||||
return namedTag;
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
tag = new ErrorTag( "IOException while reading tag type:\n" + ex.getMessage() );
|
||||
throw new RuntimeException( "Exception reading tag", ex );
|
||||
}
|
||||
} else
|
||||
{
|
||||
tag = NamedTag.read( in );
|
||||
}
|
||||
Preconditions.checkArgument( !tag.isError(), "Error reading tag: %s", tag.error() );
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static void writeTag(Tag tag, ByteBuf output, int protocolVersion)
|
||||
@ -486,11 +487,11 @@ public abstract class DefinedPacket
|
||||
DataOutputStream out = new DataOutputStream( new ByteBufOutputStream( output ) );
|
||||
try
|
||||
{
|
||||
if ( tag instanceof SpecificTag )
|
||||
if ( tag instanceof TypedTag )
|
||||
{
|
||||
SpecificTag specificTag = (SpecificTag) tag;
|
||||
specificTag.writeType( out );
|
||||
specificTag.write( out );
|
||||
TypedTag typedTag = (TypedTag) tag;
|
||||
out.writeByte( typedTag.getId() );
|
||||
typedTag.write( out );
|
||||
} else
|
||||
{
|
||||
tag.write( out );
|
||||
|
@ -12,12 +12,17 @@ import lombok.Setter;
|
||||
public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf>
|
||||
{
|
||||
|
||||
public MinecraftDecoder(Protocol protocol, boolean server, int protocolVersion)
|
||||
{
|
||||
this( protocol, server, protocolVersion, shouldCopyBuffer( protocol, protocolVersion ) );
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Protocol protocol;
|
||||
private final boolean server;
|
||||
@Setter
|
||||
private int protocolVersion;
|
||||
private boolean copyBuffer;
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
|
||||
@ -30,8 +35,7 @@ public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf>
|
||||
}
|
||||
|
||||
Protocol.DirectionData prot = ( server ) ? protocol.TO_SERVER : protocol.TO_CLIENT;
|
||||
ByteBuf slice = in.copy(); // Can't slice this one due to EntityMap :(
|
||||
|
||||
ByteBuf slice = ( copyBuffer ) ? in.copy() : in.retainedSlice();
|
||||
try
|
||||
{
|
||||
int packetId = DefinedPacket.readVarInt( in );
|
||||
@ -60,4 +64,17 @@ public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setProtocol(Protocol protocol)
|
||||
{
|
||||
this.protocol = protocol;
|
||||
this.copyBuffer = shouldCopyBuffer( protocol, protocolVersion );
|
||||
}
|
||||
|
||||
private static boolean shouldCopyBuffer(Protocol protocol, int protocolVersion)
|
||||
{
|
||||
// We only use the entity map in game state, we can avoid many buffer copies by checking this
|
||||
// EntityMap is removed for 1.20.2 and up
|
||||
return protocol == Protocol.GAME && protocolVersion < ProtocolConstants.MINECRAFT_1_20_2;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user