diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java b/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java index 3b658b39a..1d0d72403 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java @@ -1,28 +1,18 @@ package net.md_5.bungee.api.chat; import com.google.common.base.Preconditions; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.ToString; +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; @Getter @ToString @@ -53,7 +43,8 @@ public final class HoverEvent */ public HoverEvent(Action action, Content... contents) { - Preconditions.checkArgument( contents.length != 0, "Must contain at least one content" ); + Preconditions.checkArgument( contents.length != 0, + "Must contain at least one content" ); this.action = action; this.contents = new ArrayList<>(); for ( Content it : contents ) @@ -75,7 +66,7 @@ public final class HoverEvent // Old plugins may have somehow hacked BaseComponent[] into // anything other than SHOW_TEXT action. Ideally continue support. this.action = action; - this.contents = new ArrayList<>( Collections.singletonList( new ContentText( value ) ) ); + this.contents = new ArrayList<>( Collections.singletonList( new Text( value ) ) ); this.legacy = true; } @@ -90,249 +81,12 @@ public final class HoverEvent */ public void addContent(Content content) throws UnsupportedOperationException { - Preconditions.checkArgument( !legacy || contents.size() == 0, "Legacy HoverEvent may not have more than one content" ); + Preconditions.checkArgument( !legacy || contents.size() == 0, + "Legacy HoverEvent may not have more than one content" ); content.assertAction( action ); contents.add( content ); } - @ToString - @EqualsAndHashCode - public abstract static class Content - { - - /** - * Required action for this content type. - * - * @return action - */ - abstract Action requiredAction(); - - /** - * Tests this content against an action - * - * @param input input to test - * @throws UnsupportedOperationException if action incompatible - */ - void assertAction(Action input) throws UnsupportedOperationException - { - if ( input != requiredAction() ) - { - throw new UnsupportedOperationException( "Action " + input + " not compatible! Expected " + requiredAction() ); - } - } - } - - @Data - @ToString - public static class ContentText extends Content - { - - /** - * The value. - * - * May be a component or raw text depending on constructor used. - */ - private Object value; - - public ContentText(BaseComponent[] value) - { - this.value = value; - } - - public ContentText(String value) - { - this.value = value; - } - - @Override - Action requiredAction() - { - return Action.SHOW_TEXT; - } - - @Override - public boolean equals(Object o) - { - if ( value instanceof BaseComponent[] ) - { - return o instanceof ContentText - && ( (ContentText) o ).value instanceof BaseComponent[] - && Arrays.equals( (BaseComponent[]) value, (BaseComponent[]) ( (ContentText) o ).value ); - } else - { - return value.equals( o ); - } - } - - @Override - public int hashCode() - { - return ( value instanceof BaseComponent[] ) ? Arrays.hashCode( (BaseComponent[]) value ) : value.hashCode(); - } - - public static class Serializer implements JsonSerializer, JsonDeserializer - { - - @Override - public ContentText deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException - { - if ( element.isJsonArray() ) - { - return new ContentText( context.deserialize( element, BaseComponent[].class ) ); - } else if ( element.getAsJsonObject().isJsonPrimitive() ) - { - return new ContentText( element.getAsJsonObject().getAsJsonPrimitive().getAsString() ); - } else - { - return new ContentText( new BaseComponent[] - { - context.deserialize( element, BaseComponent.class ) - } ); - } - } - - @Override - public JsonElement serialize(ContentText content, Type type, JsonSerializationContext context) - { - return context.serialize( content.getValue() ); - } - } - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - @ToString - @EqualsAndHashCode(callSuper = true) - public static class ContentEntity extends Content - { - - /** - * Namespaced entity ID. - * - * Will use 'minecraft:pig' if null. - */ - private String type; - /** - * Entity UUID in hyphenated hexadecimal format. - * - * Should be valid UUID. TODO : validate? - */ - @NonNull - private String id; - /** - * Name to display as the entity. - * - * This is optional and will be hidden if null. - */ - private BaseComponent name; - - @Override - Action requiredAction() - { - return Action.SHOW_ENTITY; - } - - public static class Serializer implements JsonSerializer, JsonDeserializer - { - - @Override - public ContentEntity deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException - { - JsonObject value = element.getAsJsonObject(); - - return new ContentEntity( - ( value.has( "type" ) ) ? value.get( "type" ).getAsString() : null, - value.get( "id" ).getAsString(), - ( value.has( "name" ) ) ? context.deserialize( value.get( "name" ), BaseComponent.class ) : null - ); - } - - @Override - public JsonElement serialize(ContentEntity content, Type type, JsonSerializationContext context) - { - JsonObject object = new JsonObject(); - object.addProperty( "type", ( content.getType() != null ) ? content.getType() : "minecraft:pig" ); - object.addProperty( "id", content.getId() ); - if ( content.getName() != null ) - { - object.add( "name", context.serialize( content.getName() ) ); - } - return object; - } - } - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - @ToString - @EqualsAndHashCode(callSuper = true) - public static class ContentItem extends Content - { - - /** - * Namespaced item ID. Will use 'minecraft:air' if null. - */ - private String id; - /** - * Optional. Size of the item stack. - */ - private int count = -1; - /** - * Optional. Item tag. - */ - private ItemTag tag; - - @Override - Action requiredAction() - { - return Action.SHOW_ITEM; - } - - public static class Serializer implements JsonSerializer, JsonDeserializer - { - - @Override - public ContentItem deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException - { - JsonObject value = element.getAsJsonObject(); - - int count = -1; - if ( value.has( "Count" ) ) - { - JsonPrimitive countObj = value.get( "Count" ).getAsJsonPrimitive(); - count = ( countObj.isString() ) - // NBT can serialize as {#int"b"} so remove the b - ? Integer.parseInt( countObj.getAsString().substring( countObj.getAsString().length() - 1 ) ) - : countObj.getAsInt(); - } - - return new ContentItem( - ( value.has( "id" ) ) ? value.get( "id" ).getAsString() : null, - count, - ( value.has( "tag" ) ) ? context.deserialize( value.get( "tag" ), ItemTag.class ) : null - ); - } - - @Override - public JsonElement serialize(ContentItem content, Type type, JsonSerializationContext context) - { - JsonObject object = new JsonObject(); - object.addProperty( "id", ( content.getId() == null ) ? "minecraft:air" : content.getId() ); - if ( content.getCount() != -1 ) - { - object.addProperty( "Count", content.getCount() ); - } - if ( content.getTag() != null ) - { - object.add( "tag", context.serialize( content.getTag() ) ); - } - return object; - } - } - } - public enum Action { @@ -363,11 +117,11 @@ public final class HoverEvent switch ( action ) { case SHOW_TEXT: - return ( array ) ? HoverEvent.ContentText[].class : HoverEvent.ContentText.class; + return ( array ) ? Text[].class : Text.class; case SHOW_ENTITY: - return ( array ) ? HoverEvent.ContentEntity[].class : HoverEvent.ContentEntity.class; + return ( array ) ? Entity[].class : Entity.class; case SHOW_ITEM: - return ( array ) ? HoverEvent.ContentItem[].class : HoverEvent.ContentItem.class; + return ( array ) ? Item[].class : Item.class; default: throw new UnsupportedOperationException( "Action '" + action.name() + " not supported" ); } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ItemTag.java b/chat/src/main/java/net/md_5/bungee/api/chat/ItemTag.java index f2b1bc914..d05e5d8b7 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/ItemTag.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/ItemTag.java @@ -1,20 +1,18 @@ package net.md_5.bungee.api.chat; -import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import java.lang.reflect.Type; -import java.util.ArrayList; import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.EqualsAndHashCode; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.Singular; @@ -23,23 +21,32 @@ import lombok.ToString; /** * Metadata for use in conjunction with {@link HoverEvent.Action#SHOW_ITEM} */ -@ToString(callSuper = true) +@Builder(builderClassName = "Builder", access = AccessLevel.PRIVATE) +@ToString(of = "nbt") +@EqualsAndHashCode(of = "nbt") @Setter -@Builder(builderClassName = "Builder", access = AccessLevel.PUBLIC) @AllArgsConstructor -@EqualsAndHashCode public final class ItemTag { + @Getter + private final String nbt; + private BaseComponent name; @Singular("ench") - private List enchantments = new ArrayList<>(); + private List enchantments; @Singular("lore") - private List lore = new ArrayList<>(); + private List lore; private Boolean unbreakable; - private ItemTag() + private ItemTag(String nbt) { + this.nbt = nbt; + } + + public static ItemTag ofNbt(String nbt) + { + return new ItemTag( nbt ); } @RequiredArgsConstructor @@ -56,103 +63,13 @@ public final class ItemTag @Override public ItemTag deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException { - ItemTag itemTag = new ItemTag(); - JsonObject object = element.getAsJsonObject(); - if ( object.has( "ench" ) ) - { - for ( JsonElement jsonElement : object.get( "ench" ).getAsJsonArray() ) - { - JsonObject next = jsonElement.getAsJsonObject(); - itemTag.enchantments.add( new Enchantment( next.get( "id" ).getAsInt(), next.get( "lvl" ).getAsInt() ) ); - } - } - if ( object.has( "Unbreakable" ) ) - { - int status = object.get( "Unbreakable" ).getAsInt(); - if ( status == 1 ) - { - itemTag.unbreakable = true; - } else if ( status == 0 ) - { - itemTag.unbreakable = false; - } - } - if ( object.has( "display" ) ) - { - JsonObject display = object.get( "display" ).getAsJsonObject(); - if ( display.has( "Name" ) ) - { - itemTag.name = context.deserialize( display.get( "Name" ).getAsJsonObject(), BaseComponent.class ); - } - - if ( display.has( "Lore" ) ) - { - JsonElement lore = display.get( "Lore" ); - if ( lore.isJsonArray() ) - { - for ( JsonElement loreIt : lore.getAsJsonArray() ) - { - if ( loreIt.isJsonArray() ) - { - itemTag.lore.add( context.deserialize( loreIt, BaseComponent[].class ) ); - } else - { - itemTag.lore.add( new BaseComponent[] - { - context.deserialize( loreIt, BaseComponent.class ) - } ); - } - } - } else - { - itemTag.lore.add( context.deserialize( display.get( "Lore" ), BaseComponent[].class ) ); - } - } - } - return itemTag; + return ofNbt( element.toString().replace( "\"", "" ) ); } @Override public JsonElement serialize(ItemTag itemTag, Type type, JsonSerializationContext context) { - JsonObject object = new JsonObject(); - - if ( !itemTag.enchantments.isEmpty() ) - { - JsonArray enchArray = new JsonArray(); - for ( Enchantment ench : itemTag.enchantments ) - { - JsonObject enchObj = new JsonObject(); - enchObj.addProperty( "id", ench.id ); - enchObj.addProperty( "lvl", ench.level ); - enchArray.add( enchObj ); - } - object.add( "ench", enchArray ); - } - - if ( itemTag.unbreakable != null ) - { - object.addProperty( "Unbreakable", ( itemTag.unbreakable ) ? 1 : 0 ); - } - - JsonObject display = new JsonObject(); - - if ( itemTag.name != null ) - { - display.add( "Name", context.serialize( itemTag.name ) ); - } - - if ( !itemTag.lore.isEmpty() ) - { - display.add( "Lore", context.serialize( itemTag.lore ) ); - } - - if ( display.size() != 0 ) - { - object.add( "display", display ); - } - - return object; + return context.serialize( itemTag.getNbt() ); } } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Content.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Content.java new file mode 100644 index 000000000..907a1334c --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Content.java @@ -0,0 +1,32 @@ +package net.md_5.bungee.api.chat.hover.content; + +import lombok.EqualsAndHashCode; +import lombok.ToString; +import net.md_5.bungee.api.chat.HoverEvent; + +@ToString +@EqualsAndHashCode +public abstract class Content +{ + + /** + * Required action for this content type. + * + * @return action + */ + public abstract HoverEvent.Action requiredAction(); + + /** + * Tests this content against an action + * + * @param input input to test + * @throws UnsupportedOperationException if action incompatible + */ + public void assertAction(HoverEvent.Action input) throws UnsupportedOperationException + { + if ( input != requiredAction() ) + { + throw new UnsupportedOperationException( "Action " + input + " not compatible! Expected " + requiredAction() ); + } + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Entity.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Entity.java new file mode 100644 index 000000000..bbe708e96 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Entity.java @@ -0,0 +1,43 @@ +package net.md_5.bungee.api.chat.hover.content; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.ToString; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.HoverEvent; + +@Data +@AllArgsConstructor +@ToString +@EqualsAndHashCode(callSuper = true) +public class Entity extends Content +{ + + /** + * Namespaced entity ID. + * + * Will use 'minecraft:pig' if null. + */ + private String type; + /** + * Entity UUID in hyphenated hexadecimal format. + * + * Should be valid UUID. TODO : validate? + */ + @NonNull + private String id; + /** + * Name to display as the entity. + * + * This is optional and will be hidden if null. + */ + private BaseComponent name; + + @Override + public HoverEvent.Action requiredAction() + { + return HoverEvent.Action.SHOW_ENTITY; + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java new file mode 100644 index 000000000..531433262 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/EntitySerializer.java @@ -0,0 +1,40 @@ +package net.md_5.bungee.api.chat.hover.content; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import net.md_5.bungee.api.chat.BaseComponent; + +public class EntitySerializer implements JsonSerializer, JsonDeserializer +{ + + @Override + public Entity deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException + { + JsonObject value = element.getAsJsonObject(); + + return new Entity( + ( value.has( "type" ) ) ? value.get( "type" ).getAsString() : null, + value.get( "id" ).getAsString(), + ( value.has( "name" ) ) ? context.deserialize( value.get( "name" ), BaseComponent.class ) : null + ); + } + + @Override + public JsonElement serialize(Entity content, Type type, JsonSerializationContext context) + { + JsonObject object = new JsonObject(); + object.addProperty( "type", ( content.getType() != null ) ? content.getType() : "minecraft:pig" ); + object.addProperty( "id", content.getId() ); + if ( content.getName() != null ) + { + object.add( "name", context.serialize( content.getName() ) ); + } + return object; + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Item.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Item.java new file mode 100644 index 000000000..4a97a3ab2 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Item.java @@ -0,0 +1,35 @@ +package net.md_5.bungee.api.chat.hover.content; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.ItemTag; + +@Data +@AllArgsConstructor +@ToString +@EqualsAndHashCode(callSuper = false) +public class Item extends Content +{ + + /** + * Namespaced item ID. Will use 'minecraft:air' if null. + */ + private String id; + /** + * Optional. Size of the item stack. + */ + private int count = -1; + /** + * Optional. Item tag. + */ + private ItemTag tag; + + @Override + public HoverEvent.Action requiredAction() + { + return HoverEvent.Action.SHOW_ITEM; + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java new file mode 100644 index 000000000..0ba8f0b92 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/ItemSerializer.java @@ -0,0 +1,69 @@ +package net.md_5.bungee.api.chat.hover.content; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import net.md_5.bungee.api.chat.ItemTag; + +public class ItemSerializer implements JsonSerializer, JsonDeserializer +{ + + @Override + public Item deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException + { + JsonObject value = element.getAsJsonObject(); + + int count = -1; + if ( value.has( "Count" ) ) + { + JsonPrimitive countObj = value.get( "Count" ).getAsJsonPrimitive(); + + if ( countObj.isNumber() ) + { + count = countObj.getAsInt(); + } else if ( countObj.isString() ) + { + String cString = countObj.getAsString(); + if ( cString.endsWith( "b" ) ) + { + cString = cString.substring( 0, cString.length() - 1 ); + } + try + { + count = Integer.parseInt( cString ); + } catch ( NumberFormatException ex ) + { + throw new JsonParseException( "Could not parse count: " + ex ); + } + } + } + + return new Item( + ( value.has( "id" ) ) ? value.get( "id" ).getAsString() : null, + count, + ( value.has( "tag" ) ) ? context.deserialize( value.get( "tag" ), ItemTag.class ) : null + ); + } + + @Override + public JsonElement serialize(Item content, Type type, JsonSerializationContext context) + { + JsonObject object = new JsonObject(); + object.addProperty( "id", ( content.getId() == null ) ? "minecraft:air" : content.getId() ); + if ( content.getCount() != -1 ) + { + object.addProperty( "Count", content.getCount() ); + } + if ( content.getTag() != null ) + { + object.add( "tag", context.serialize( content.getTag() ) ); + } + return object; + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Text.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Text.java new file mode 100644 index 000000000..58a343aa8 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/Text.java @@ -0,0 +1,56 @@ +package net.md_5.bungee.api.chat.hover.content; + +import java.util.Arrays; +import lombok.Getter; +import lombok.ToString; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.HoverEvent; + +@Getter +@ToString +public class Text extends Content +{ + + /** + * The value. + * + * May be a component or raw text depending on constructor used. + */ + private final Object value; + + public Text(BaseComponent[] value) + { + this.value = value; + } + + public Text(String value) + { + this.value = value; + } + + @Override + public HoverEvent.Action requiredAction() + { + return HoverEvent.Action.SHOW_TEXT; + } + + @Override + public boolean equals(Object o) + { + if ( value instanceof BaseComponent[] ) + { + return o instanceof Text + && ( (Text) o ).value instanceof BaseComponent[] + && Arrays.equals( (BaseComponent[]) value, (BaseComponent[]) ( (Text) o ).value ); + } else + { + return value.equals( o ); + } + } + + @Override + public int hashCode() + { + return ( value instanceof BaseComponent[] ) ? Arrays.hashCode( (BaseComponent[]) value ) : value.hashCode(); + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java new file mode 100644 index 000000000..d5f66a5be --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/hover/content/TextSerializer.java @@ -0,0 +1,38 @@ +package net.md_5.bungee.api.chat.hover.content; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import net.md_5.bungee.api.chat.BaseComponent; + +public class TextSerializer implements JsonSerializer, JsonDeserializer +{ + + @Override + public Text deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException + { + if ( element.isJsonArray() ) + { + return new Text( context.deserialize( element, BaseComponent[].class ) ); + } else if ( element.getAsJsonObject().isJsonPrimitive() ) + { + return new Text( element.getAsJsonObject().getAsJsonPrimitive().getAsString() ); + } else + { + return new Text( new BaseComponent[] + { + context.deserialize( element, BaseComponent.class ) + } ); + } + } + + @Override + public JsonElement serialize(Text content, Type type, JsonSerializationContext context) + { + return context.serialize( content.getValue() ); + } +} diff --git a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java index a08f5cc76..4387841bf 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java @@ -14,6 +14,7 @@ import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.hover.content.Content; public class BaseComponentSerializer { @@ -77,14 +78,14 @@ public class BaseComponentSerializer { continue; } - HoverEvent.Content[] list; + Content[] list; JsonElement contents = event.get( type ); if ( contents.isJsonArray() ) { list = context.deserialize( contents, HoverEvent.getClass( action, true ) ); } else { - list = new HoverEvent.Content[] + list = new Content[] { context.deserialize( contents, HoverEvent.getClass( action, false ) ) }; diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java index 9dd751b02..34b6e3a38 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java @@ -11,13 +11,18 @@ import com.google.gson.JsonParser; import java.lang.reflect.Type; import java.util.Set; import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.ItemTag; import net.md_5.bungee.api.chat.KeybindComponent; import net.md_5.bungee.api.chat.ScoreComponent; import net.md_5.bungee.api.chat.SelectorComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TranslatableComponent; +import net.md_5.bungee.api.chat.hover.content.Entity; +import net.md_5.bungee.api.chat.hover.content.EntitySerializer; +import net.md_5.bungee.api.chat.hover.content.Item; +import net.md_5.bungee.api.chat.hover.content.ItemSerializer; +import net.md_5.bungee.api.chat.hover.content.Text; +import net.md_5.bungee.api.chat.hover.content.TextSerializer; public class ComponentSerializer implements JsonDeserializer { @@ -30,9 +35,9 @@ public class ComponentSerializer implements JsonDeserializer registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ). registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ). registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ). - registerTypeAdapter( HoverEvent.ContentEntity.class, new HoverEvent.ContentEntity.Serializer() ). - registerTypeAdapter( HoverEvent.ContentText.class, new HoverEvent.ContentText.Serializer() ). - registerTypeAdapter( HoverEvent.ContentItem.class, new HoverEvent.ContentItem.Serializer() ). + registerTypeAdapter( Entity.class, new EntitySerializer() ). + registerTypeAdapter( Text.class, new TextSerializer() ). + registerTypeAdapter( Item.class, new ItemSerializer() ). registerTypeAdapter( ItemTag.class, new ItemTag.Serializer() ). create(); diff --git a/chat/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java index 657fde2a9..a9347fe0b 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/TextComponentSerializer.java @@ -20,8 +20,12 @@ public class TextComponentSerializer extends BaseComponentSerializer implements { TextComponent component = new TextComponent(); JsonObject object = json.getAsJsonObject(); - deserialize( object, component, context ); + if ( !object.has( "text" ) ) + { + throw new JsonParseException( "Could not parse JSON: missing 'text' property" ); + } component.setText( object.get( "text" ).getAsString() ); + deserialize( object, component, context ); return component; } diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java b/chat/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java index 6f1400e24..3c14d275a 100644 --- a/chat/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java +++ b/chat/src/test/java/net/md_5/bungee/api/chat/ComponentsTest.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import net.md_5.bungee.api.ChatColor; +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.ComponentSerializer; import org.junit.Assert; import org.junit.Test; @@ -20,6 +22,19 @@ public class ComponentsTest String serialised = ComponentSerializer.toString( component ); BaseComponent[] deserialised = ComponentSerializer.parse( serialised ); Assert.assertEquals( TextComponent.toLegacyText( deserialised ), TextComponent.toLegacyText( component ) ); + ////////// + TextComponent component1 = new TextComponent( "HoverableText" ); + String nbt = "{display:{Name:{text:Hello},Lore:[{text:Line_1},{text:Line_2}]},ench:[{id:49,lvl:5}],Unbreakable:1}}"; + Item contentItem = new Item( "minecraft:wood", 1, ItemTag.ofNbt( nbt ) ); + HoverEvent hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_ITEM, contentItem ); + component1.setHoverEvent( hoverEvent ); + json = ComponentSerializer.toString( component1 ); + component = ComponentSerializer.parse( json ); + Item parsedContentItem = ( (Item) component[0].getHoverEvent().getContents().get( 0 ) ); + Assert.assertEquals( contentItem, parsedContentItem ); + Assert.assertEquals( contentItem.getCount(), parsedContentItem.getCount() ); + Assert.assertEquals( contentItem.getId(), parsedContentItem.getId() ); + Assert.assertEquals( nbt, parsedContentItem.getTag().getNbt() ); } @Test @@ -134,6 +149,7 @@ public class ComponentsTest ); } + /* @Test public void testItemTag() { @@ -154,6 +170,7 @@ public class ComponentsTest BaseComponent[] deserialised = ComponentSerializer.parse( serialised ); Assert.assertEquals( TextComponent.toLegacyText( deserialised ), TextComponent.toLegacyText( component ) ); } + */ @Test public void testModernShowAdvancement() @@ -162,13 +179,13 @@ public class ComponentsTest // First do the text using the newer contents system HoverEvent hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, - new HoverEvent.ContentText( advancement ) + new Text( advancement ) ); TextComponent component = new TextComponent( "test" ); component.setHoverEvent( hoverEvent ); Assert.assertEquals( component.getHoverEvent().getContents().size(), 1 ); - Assert.assertTrue( component.getHoverEvent().getContents().get( 0 ) instanceof HoverEvent.ContentText ); - Assert.assertEquals( ( (HoverEvent.ContentText) component.getHoverEvent().getContents().get( 0 ) ).getValue(), advancement ); + Assert.assertTrue( component.getHoverEvent().getContents().get( 0 ) instanceof Text ); + Assert.assertEquals( ( (Text) component.getHoverEvent().getContents().get( 0 ) ).getValue(), advancement ); } @Test @@ -177,8 +194,8 @@ public class ComponentsTest // First do the text using the newer contents system HoverEvent hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, - new HoverEvent.ContentText( new ComponentBuilder( "First" ).create() ), - new HoverEvent.ContentText( new ComponentBuilder( "Second" ).create() ) + new Text( new ComponentBuilder( "First" ).create() ), + new Text( new ComponentBuilder( "Second" ).create() ) ); TextComponent component = new TextComponent( "Sample text" ); diff --git a/proxy/src/main/java/net/md_5/bungee/util/ChatComponentTransformer.java b/proxy/src/main/java/net/md_5/bungee/util/ChatComponentTransformer.java index f0324f22b..29d2a1670 100644 --- a/proxy/src/main/java/net/md_5/bungee/util/ChatComponentTransformer.java +++ b/proxy/src/main/java/net/md_5/bungee/util/ChatComponentTransformer.java @@ -7,9 +7,9 @@ import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.NoArgsConstructor; import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.ScoreComponent; import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Content; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.score.Score; import net.md_5.bungee.protocol.ProtocolConstants; @@ -49,7 +49,7 @@ public final class ChatComponentTransformer next.getHoverEvent().setLegacy( true ); if ( next.getHoverEvent().getContents().size() > 1 ) { - HoverEvent.Content exception = next.getHoverEvent().getContents().get( 0 ); + Content exception = next.getHoverEvent().getContents().get( 0 ); next.getHoverEvent().getContents().clear(); next.getHoverEvent().getContents().add( exception ); }