#2893: Refactored Hover Code for Maintainability
This commit is contained in:
parent
4794fccfb8
commit
bcc3460dda
@ -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<ContentText>, JsonDeserializer<ContentText>
|
||||
{
|
||||
|
||||
@Override
|
||||
public ContentText deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
if ( element.isJsonArray() )
|
||||
{
|
||||
return new ContentText( context.<BaseComponent[]>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<ContentEntity>, JsonDeserializer<ContentEntity>
|
||||
{
|
||||
|
||||
@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<ContentItem>, JsonDeserializer<ContentItem>
|
||||
{
|
||||
|
||||
@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" );
|
||||
}
|
||||
|
@ -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<Enchantment> enchantments = new ArrayList<>();
|
||||
private List<Enchantment> enchantments;
|
||||
@Singular("lore")
|
||||
private List<BaseComponent[]> lore = new ArrayList<>();
|
||||
private List<BaseComponent[]> 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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() );
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<Entity>, JsonDeserializer<Entity>
|
||||
{
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<Item>, JsonDeserializer<Item>
|
||||
{
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<Text>, JsonDeserializer<Text>
|
||||
{
|
||||
|
||||
@Override
|
||||
public Text deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
if ( element.isJsonArray() )
|
||||
{
|
||||
return new Text( context.<BaseComponent[]>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() );
|
||||
}
|
||||
}
|
@ -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 ) )
|
||||
};
|
||||
|
@ -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<BaseComponent>
|
||||
{
|
||||
@ -30,9 +35,9 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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" );
|
||||
|
@ -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 );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user