Minecraft 25w20a protocol support

This commit is contained in:
md_5
2025-05-17 16:01:00 +10:00
parent a336efb8fa
commit 69e4872f40
67 changed files with 1530 additions and 41 deletions

View File

@@ -4,12 +4,14 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.jetbrains.annotations.ApiStatus;
@Getter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
public final class ClickEvent
@ApiStatus.NonExtendable
public class ClickEvent
{
/**
@@ -52,11 +54,19 @@ public final class ClickEvent
* {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book.
*/
CHANGE_PAGE,
/**
* Must use subclass ShowDialogClickEvent.
*/
SHOW_DIALOG,
/**
* Copy the string given by
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's
* clipboard.
*/
COPY_TO_CLIPBOARD
COPY_TO_CLIPBOARD,
/**
* Must use subclass {@link ClickEventCustom}.
*/
CUSTOM,
}
}

View File

@@ -0,0 +1,30 @@
package net.md_5.bungee.api.chat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* Click event which sends a custom payload to the server.
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class ClickEventCustom extends ClickEvent
{
/**
* The custom payload.
*/
private final String payload;
/**
* @param id identifier for the event (lower case, no special characters)
* @param payload custom payload
*/
public ClickEventCustom(String id, String payload)
{
super( ClickEvent.Action.CUSTOM, id );
this.payload = payload;
}
}

View File

@@ -13,7 +13,6 @@ import net.md_5.bungee.api.chat.hover.content.Content;
import net.md_5.bungee.api.chat.hover.content.Entity;
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.chat.VersionedComponentSerializer;
import org.jetbrains.annotations.ApiStatus;
@Getter
@@ -73,22 +72,6 @@ public final class HoverEvent
this.legacy = true;
}
@Deprecated
public BaseComponent[] getValue()
{
Content content = contents.get( 0 );
if ( content instanceof Text && ( (Text) content ).getValue() instanceof BaseComponent[] )
{
return (BaseComponent[]) ( (Text) content ).getValue();
}
TextComponent component = new TextComponent( VersionedComponentSerializer.getDefault().toString( content ) );
return new BaseComponent[]
{
component
};
}
/**
* Adds a content to this hover event.
*

View File

@@ -1,78 +0,0 @@
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 java.util.UUID;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.chat.BaseComponentSerializer;
import net.md_5.bungee.chat.VersionedComponentSerializer;
public class EntitySerializer extends BaseComponentSerializer implements JsonSerializer<Entity>, JsonDeserializer<Entity>
{
public EntitySerializer(VersionedComponentSerializer serializer)
{
super( serializer );
}
@Override
public Entity deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{
JsonObject value = element.getAsJsonObject();
boolean newEntity = value.has( "uuid" );
String idString;
JsonElement uuid = value.get( newEntity ? "uuid" : "id" );
if ( uuid.isJsonArray() )
{
idString = parseUUID( context.deserialize( uuid, int[].class ) ).toString();
} else
{
idString = uuid.getAsString();
}
return new Entity(
( value.has( newEntity ? "id" : "type" ) ) ? value.get( newEntity ? "id" : "type" ).getAsString() : null,
idString,
( 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();
switch ( serializer.getVersion() )
{
case V1_21_5:
object.addProperty( "id", ( content.getType() != null ) ? content.getType() : "minecraft:pig" );
object.addProperty( "uuid", content.getId() );
break;
case V1_16:
object.addProperty( "type", ( content.getType() != null ) ? content.getType() : "minecraft:pig" );
object.addProperty( "id", content.getId() );
break;
default:
throw new IllegalArgumentException( "Unknown version " + serializer.getVersion() );
}
if ( content.getName() != null )
{
object.add( "name", context.serialize( content.getName() ) );
}
return object;
}
private static UUID parseUUID(int[] array)
{
return new UUID( (long) array[0] << 32 | (long) array[1] & 0XFFFFFFFFL, (long) array[2] << 32 | (long) array[3] & 0XFFFFFFFFL );
}
}

View File

@@ -1,71 +0,0 @@
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();
char last = cString.charAt( cString.length() - 1 );
// Check for all number suffixes
if ( last == 'b' || last == 's' || last == 'l' || last == 'f' || last == 'd' )
{
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;
}
}

View File

@@ -1,38 +0,0 @@
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.isJsonPrimitive() )
{
return new Text( element.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() );
}
}

View File

@@ -1,257 +0,0 @@
package net.md_5.bungee.chat;
import com.google.common.base.Preconditions;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Locale;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Content;
@RequiredArgsConstructor
public class BaseComponentSerializer
{
protected final VersionedComponentSerializer serializer;
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context)
{
component.applyStyle( context.deserialize( object, ComponentStyle.class ) );
JsonElement insertion = object.get( "insertion" );
if ( insertion != null )
{
component.setInsertion( insertion.getAsString() );
}
//Events
JsonObject clickEvent;
boolean newClickEvent = ( clickEvent = object.getAsJsonObject( "click_event" ) ) != null;
if ( !newClickEvent )
{
clickEvent = object.getAsJsonObject( "clickEvent" );
}
if ( clickEvent != null )
{
ClickEvent.Action action = ClickEvent.Action.valueOf( clickEvent.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) );
if ( newClickEvent )
{
switch ( action )
{
case OPEN_URL:
component.setClickEvent( new ClickEvent( action, clickEvent.get( "url" ).getAsString() ) );
break;
case RUN_COMMAND:
case SUGGEST_COMMAND:
component.setClickEvent( new ClickEvent( action, clickEvent.get( "command" ).getAsString() ) );
break;
case CHANGE_PAGE:
int page = clickEvent.get( "page" ).getAsInt();
Preconditions.checkArgument( page >= 0, "Page number has to be positive" );
component.setClickEvent( new ClickEvent( action, Integer.toString( page ) ) );
break;
default:
component.setClickEvent( new ClickEvent( action, ( clickEvent.has( "value" ) ) ? clickEvent.get( "value" ).getAsString() : "" ) );
break;
}
} else
{
component.setClickEvent( new ClickEvent( action, ( clickEvent.has( "value" ) ) ? clickEvent.get( "value" ).getAsString() : "" ) );
}
}
JsonObject hoverEventJson;
boolean newHoverEvent = ( hoverEventJson = object.getAsJsonObject( "hover_event" ) ) != null;
if ( !newHoverEvent )
{
hoverEventJson = object.getAsJsonObject( "hoverEvent" );
}
if ( hoverEventJson != null )
{
HoverEvent hoverEvent = null;
HoverEvent.Action action = HoverEvent.Action.valueOf( hoverEventJson.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) );
if ( newHoverEvent || hoverEventJson.has( "contents" ) )
{
// value is only used for text in >= 1.21.5 (its inlined now)
JsonElement contents = hoverEventJson.get( newHoverEvent ? "value" : "contents" );
if ( contents != null || ( newHoverEvent && ( action == HoverEvent.Action.SHOW_ITEM || action == HoverEvent.Action.SHOW_ENTITY ) ) )
{
if ( contents == null )
{
// this is the new inline for SHOW_ITEM and SHOW_ENTITY
contents = hoverEventJson;
}
Content[] list;
if ( contents.isJsonArray() )
{
list = context.deserialize( contents, HoverEvent.getClass( action, true ) );
} else
{
list = new Content[]
{
context.deserialize( contents, HoverEvent.getClass( action, false ) )
};
}
hoverEvent = new HoverEvent( action, new ArrayList<>( Arrays.asList( list ) ) );
}
} else
{
JsonElement value = hoverEventJson.get( "value" );
if ( value != null )
{
// Plugins previously had support to pass BaseComponent[] into any action.
// If the GSON is possible to be parsed as BaseComponent, attempt to parse as so.
BaseComponent[] components;
if ( value.isJsonArray() )
{
components = context.deserialize( value, BaseComponent[].class );
} else
{
components = new BaseComponent[]
{
context.deserialize( value, BaseComponent.class )
};
}
hoverEvent = new HoverEvent( action, components );
}
}
if ( hoverEvent != null )
{
component.setHoverEvent( hoverEvent );
}
}
JsonElement extra = object.get( "extra" );
if ( extra != null )
{
component.setExtra( Arrays.asList( context.deserialize( extra, BaseComponent[].class ) ) );
}
}
protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context)
{
boolean first = false;
if ( VersionedComponentSerializer.serializedComponents.get() == null )
{
first = true;
VersionedComponentSerializer.serializedComponents.set( Collections.newSetFromMap( new IdentityHashMap<BaseComponent, Boolean>() ) );
}
try
{
Preconditions.checkArgument( !VersionedComponentSerializer.serializedComponents.get().contains( component ), "Component loop" );
VersionedComponentSerializer.serializedComponents.get().add( component );
ComponentStyleSerializer.serializeTo( component.getStyle(), object );
if ( component.getInsertion() != null )
{
object.addProperty( "insertion", component.getInsertion() );
}
//Events
if ( component.getClickEvent() != null )
{
JsonObject clickEvent = new JsonObject();
String actionName = component.getClickEvent().getAction().toString().toLowerCase( Locale.ROOT );
clickEvent.addProperty( "action", actionName.toLowerCase( Locale.ROOT ) );
switch ( serializer.getVersion() )
{
case V1_21_5:
ClickEvent.Action action = ClickEvent.Action.valueOf( actionName.toUpperCase( Locale.ROOT ) );
switch ( action )
{
case OPEN_URL:
clickEvent.addProperty( "url", component.getClickEvent().getValue() );
break;
case RUN_COMMAND:
case SUGGEST_COMMAND:
clickEvent.addProperty( "command", component.getClickEvent().getValue() );
break;
case CHANGE_PAGE:
clickEvent.addProperty( "page", Integer.parseInt( component.getClickEvent().getValue() ) );
break;
default:
clickEvent.addProperty( "value", component.getClickEvent().getValue() );
break;
}
object.add( "click_event", clickEvent );
break;
case V1_16:
clickEvent.addProperty( "value", component.getClickEvent().getValue() );
object.add( "clickEvent", clickEvent );
break;
default:
throw new IllegalArgumentException( "Unknown version " + serializer.getVersion() );
}
}
if ( component.getHoverEvent() != null )
{
JsonObject hoverEvent = new JsonObject();
hoverEvent.addProperty( "action", component.getHoverEvent().getAction().toString().toLowerCase( Locale.ROOT ) );
if ( component.getHoverEvent().isLegacy() )
{
hoverEvent.add( "value", context.serialize( component.getHoverEvent().getContents().get( 0 ) ) );
} else
{
switch ( serializer.getVersion() )
{
case V1_21_5:
if ( component.getHoverEvent().getAction() == HoverEvent.Action.SHOW_ITEM || component.getHoverEvent().getAction() == HoverEvent.Action.SHOW_ENTITY )
{
JsonObject inlined = context.serialize( ( component.getHoverEvent().getContents().size() == 1 )
? component.getHoverEvent().getContents().get( 0 ) : component.getHoverEvent().getContents() ).getAsJsonObject();
inlined.entrySet().forEach( entry -> hoverEvent.add( entry.getKey(), entry.getValue() ) );
} else
{
hoverEvent.add( "value", context.serialize( ( component.getHoverEvent().getContents().size() == 1 )
? component.getHoverEvent().getContents().get( 0 ) : component.getHoverEvent().getContents() ) );
}
break;
case V1_16:
hoverEvent.add( "contents", context.serialize( ( component.getHoverEvent().getContents().size() == 1 )
? component.getHoverEvent().getContents().get( 0 ) : component.getHoverEvent().getContents() ) );
break;
default:
throw new IllegalArgumentException( "Unknown version " + serializer.getVersion() );
}
}
switch ( serializer.getVersion() )
{
case V1_21_5:
object.add( "hover_event", hoverEvent );
break;
case V1_16:
object.add( "hoverEvent", hoverEvent );
break;
default:
throw new IllegalArgumentException( "Unknown version " + serializer.getVersion() );
}
}
if ( component.getExtra() != null )
{
object.add( "extra", context.serialize( component.getExtra() ) );
}
} finally
{
VersionedComponentSerializer.serializedComponents.get().remove( component );
if ( first )
{
VersionedComponentSerializer.serializedComponents.set( null );
}
}
}
}

View File

@@ -1,10 +0,0 @@
package net.md_5.bungee.chat;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public enum ChatVersion
{
V1_16,
V1_21_5;
}

View File

@@ -1,141 +0,0 @@
package net.md_5.bungee.chat;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.hover.content.Content;
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
{
/**
* Parse a JSON-compliant String as an array of base components. The input
* can be one of either an array of components, or a single component
* object. If the input is an array, each component will be parsed
* individually and returned in the order that they were parsed. If the
* input is a single component object, a single-valued array with the
* component will be returned.
* <p>
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it
* will parse only one component as opposed to an array of components which
* is non- standard behavior. This method is still appropriate for parsing
* multiple components at once, although such use case is rarely (if at all)
* exhibited in vanilla Minecraft.
*
* @param json the component json to parse
* @return an array of all parsed components
*/
public static BaseComponent[] parse(String json)
{
return VersionedComponentSerializer.getDefault().parse( json );
}
/**
* Deserialize a JSON-compliant String as a single component.
*
* @param json the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component string is passed as input
*/
public static BaseComponent deserialize(String json)
{
return VersionedComponentSerializer.getDefault().deserialize( json );
}
/**
* Deserialize a JSON element as a single component.
*
* @param jsonElement the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component is passed as input
*/
public static BaseComponent deserialize(JsonElement jsonElement)
{
return VersionedComponentSerializer.getDefault().deserialize( jsonElement );
}
/**
* Deserialize a JSON-compliant String as a component style.
*
* @param json the component style json to parse
* @return the deserialized component style
* @throws IllegalArgumentException if anything other than a valid JSON
* component style string is passed as input
*/
public static ComponentStyle deserializeStyle(String json)
{
return VersionedComponentSerializer.getDefault().deserializeStyle( json );
}
/**
* Deserialize a JSON element as a component style.
*
* @param jsonElement the component style json to parse
* @return the deserialized component style
* @throws IllegalArgumentException if anything other than a valid JSON
* component style is passed as input
*/
public static ComponentStyle deserializeStyle(JsonElement jsonElement)
{
return VersionedComponentSerializer.getDefault().deserializeStyle( jsonElement );
}
public static JsonElement toJson(BaseComponent component)
{
return VersionedComponentSerializer.getDefault().toJson( component );
}
public static JsonElement toJson(ComponentStyle style)
{
return VersionedComponentSerializer.getDefault().toJson( style );
}
/**
* @param object the object to serialize
* @return the JSON string representation of the object
* @deprecated Error-prone, be careful which object you input here
*/
@Deprecated
public static String toString(Object object)
{
return VersionedComponentSerializer.getDefault().toString( object );
}
/**
* @param content the content to serialize
* @return the JSON string representation of the object
* @deprecated for legacy internal use only
*/
@Deprecated
public static String toString(Content content)
{
return VersionedComponentSerializer.getDefault().toString( content );
}
public static String toString(BaseComponent component)
{
return VersionedComponentSerializer.getDefault().toString( component );
}
public static String toString(BaseComponent... components)
{
return VersionedComponentSerializer.getDefault().toString( components );
}
public static String toString(ComponentStyle style)
{
return VersionedComponentSerializer.getDefault().toString( style );
}
@Override
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
return VersionedComponentSerializer.getDefault().deserialize( json, typeOfT, context );
}
}

View File

@@ -1,137 +0,0 @@
package net.md_5.bungee.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.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.awt.Color;
import java.lang.reflect.Type;
import java.util.Map;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.ComponentStyleBuilder;
public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>, JsonDeserializer<ComponentStyle>
{
private static boolean getAsBoolean(JsonElement el)
{
if ( el.isJsonPrimitive() )
{
JsonPrimitive primitive = (JsonPrimitive) el;
if ( primitive.isBoolean() )
{
return primitive.getAsBoolean();
}
if ( primitive.isNumber() )
{
Number number = primitive.getAsNumber();
if ( number instanceof Byte )
{
return number.byteValue() != 0;
}
}
}
return false;
}
static void serializeTo(ComponentStyle style, JsonObject object)
{
if ( style.isBoldRaw() != null )
{
object.addProperty( "bold", style.isBoldRaw() );
}
if ( style.isItalicRaw() != null )
{
object.addProperty( "italic", style.isItalicRaw() );
}
if ( style.isUnderlinedRaw() != null )
{
object.addProperty( "underlined", style.isUnderlinedRaw() );
}
if ( style.isStrikethroughRaw() != null )
{
object.addProperty( "strikethrough", style.isStrikethroughRaw() );
}
if ( style.isObfuscatedRaw() != null )
{
object.addProperty( "obfuscated", style.isObfuscatedRaw() );
}
if ( style.hasColor() && style.getColor().getColor() != null )
{
object.addProperty( "color", style.getColor().getName() );
}
if ( style.hasShadowColor() )
{
object.addProperty( "shadow_color", style.getShadowColor().getRGB() );
}
if ( style.hasFont() )
{
object.addProperty( "font", style.getFont() );
}
}
@Override
public ComponentStyle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
ComponentStyleBuilder builder = ComponentStyle.builder();
JsonObject object = json.getAsJsonObject();
for ( Map.Entry<String, JsonElement> entry : object.entrySet() )
{
String name = entry.getKey();
JsonElement value = entry.getValue();
switch ( name )
{
case "bold":
builder.bold( getAsBoolean( value ) );
break;
case "italic":
builder.italic( getAsBoolean( value ) );
break;
case "underlined":
builder.underlined( getAsBoolean( value ) );
break;
case "strikethrough":
builder.strikethrough( getAsBoolean( value ) );
break;
case "obfuscated":
builder.obfuscated( getAsBoolean( value ) );
break;
case "color":
builder.color( ChatColor.of( value.getAsString() ) );
break;
case "shadow_color":
if ( value.isJsonArray() )
{
JsonArray array = value.getAsJsonArray();
builder.shadowColor( new Color( array.get( 0 ).getAsFloat(), array.get( 1 ).getAsFloat(), array.get( 2 ).getAsFloat(), array.get( 3 ).getAsFloat() ) );
} else if ( value.isJsonPrimitive() )
{
builder.shadowColor( new Color( value.getAsNumber().intValue(), true ) );
}
break;
case "font":
builder.font( value.getAsString() );
break;
}
}
return builder.build();
}
@Override
public JsonElement serialize(ComponentStyle src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject object = new JsonObject();
serializeTo( src, object );
return object;
}
}

View File

@@ -1,44 +0,0 @@
package net.md_5.bungee.chat;
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.KeybindComponent;
public class KeybindComponentSerializer extends BaseComponentSerializer implements JsonSerializer<KeybindComponent>, JsonDeserializer<KeybindComponent>
{
public KeybindComponentSerializer(VersionedComponentSerializer serializer)
{
super( serializer );
}
@Override
public KeybindComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
JsonObject object = json.getAsJsonObject();
JsonElement keybind = object.get( "keybind" );
if ( keybind == null )
{
throw new JsonParseException( "Could not parse JSON: missing 'keybind' property" );
}
KeybindComponent component = new KeybindComponent();
deserialize( object, component, context );
component.setKeybind( keybind.getAsString() );
return component;
}
@Override
public JsonElement serialize(KeybindComponent src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject object = new JsonObject();
serialize( object, src, context );
object.addProperty( "keybind", src.getKeybind() );
return object;
}
}

View File

@@ -1,66 +0,0 @@
package net.md_5.bungee.chat;
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.ScoreComponent;
public class ScoreComponentSerializer extends BaseComponentSerializer implements JsonSerializer<ScoreComponent>, JsonDeserializer<ScoreComponent>
{
public ScoreComponentSerializer(VersionedComponentSerializer serializer)
{
super( serializer );
}
@Override
public ScoreComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{
JsonObject json = element.getAsJsonObject();
JsonObject score = json.getAsJsonObject( "score" );
if ( score == null )
{
throw new JsonParseException( "Could not parse JSON: missing 'score' property" );
}
JsonElement nameJson = score.get( "name" );
if ( nameJson == null )
{
throw new JsonParseException( "A score component needs at least a name (and an objective)" );
}
JsonElement objectiveJson = score.get( "objective" );
if ( objectiveJson == null )
{
throw new JsonParseException( "A score component needs at least a name and an objective" );
}
String name = nameJson.getAsString();
String objective = objectiveJson.getAsString();
ScoreComponent component = new ScoreComponent( name, objective );
JsonElement value = score.get( "value" );
if ( value != null && !value.getAsString().isEmpty() )
{
component.setValue( value.getAsString() );
}
deserialize( json, component, context );
return component;
}
@Override
public JsonElement serialize(ScoreComponent component, Type type, JsonSerializationContext context)
{
JsonObject root = new JsonObject();
serialize( root, component, context );
JsonObject json = new JsonObject();
json.addProperty( "name", component.getName() );
json.addProperty( "objective", component.getObjective() );
json.addProperty( "value", component.getValue() );
root.add( "score", json );
return root;
}
}

View File

@@ -1,55 +0,0 @@
package net.md_5.bungee.chat;
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.SelectorComponent;
public class SelectorComponentSerializer extends BaseComponentSerializer implements JsonSerializer<SelectorComponent>, JsonDeserializer<SelectorComponent>
{
public SelectorComponentSerializer(VersionedComponentSerializer serializer)
{
super( serializer );
}
@Override
public SelectorComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{
JsonObject object = element.getAsJsonObject();
JsonElement selector = object.get( "selector" );
if ( selector == null )
{
throw new JsonParseException( "Could not parse JSON: missing 'selector' property" );
}
SelectorComponent component = new SelectorComponent( selector.getAsString() );
JsonElement separator = object.get( "separator" );
if ( separator != null )
{
component.setSeparator( serializer.deserialize( separator.getAsString() ) );
}
deserialize( object, component, context );
return component;
}
@Override
public JsonElement serialize(SelectorComponent component, Type type, JsonSerializationContext context)
{
JsonObject object = new JsonObject();
serialize( object, component, context );
object.addProperty( "selector", component.getSelector() );
if ( component.getSeparator() != null )
{
object.addProperty( "separator", serializer.toString( component.getSeparator() ) );
}
return object;
}
}

View File

@@ -1,43 +0,0 @@
package net.md_5.bungee.chat;
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.TextComponent;
public class TextComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TextComponent>, JsonDeserializer<TextComponent>
{
public TextComponentSerializer(VersionedComponentSerializer serializer)
{
super( serializer );
}
@Override
public TextComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
TextComponent component = new TextComponent();
JsonObject object = json.getAsJsonObject();
JsonElement text = object.get( "text" );
if ( text != null )
{
component.setText( text.getAsString() );
}
deserialize( object, component, context );
return component;
}
@Override
public JsonElement serialize(TextComponent src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject object = new JsonObject();
serialize( object, src, context );
object.addProperty( "text", src.getText() );
return object;
}
}

View File

@@ -1,64 +0,0 @@
package net.md_5.bungee.chat;
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.Arrays;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TranslatableComponent;
public class TranslatableComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TranslatableComponent>, JsonDeserializer<TranslatableComponent>
{
public TranslatableComponentSerializer(VersionedComponentSerializer serializer)
{
super( serializer );
}
@Override
public TranslatableComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
TranslatableComponent component = new TranslatableComponent();
JsonObject object = json.getAsJsonObject();
deserialize( object, component, context );
JsonElement translate = object.get( "translate" );
if ( translate == null )
{
throw new JsonParseException( "Could not parse JSON: missing 'translate' property" );
}
component.setTranslate( translate.getAsString() );
JsonElement with = object.get( "with" );
if ( with != null )
{
component.setWith( Arrays.asList( context.deserialize( with, BaseComponent[].class ) ) );
}
JsonElement fallback = object.get( "fallback" );
if ( fallback != null )
{
component.setFallback( fallback.getAsString() );
}
return component;
}
@Override
public JsonElement serialize(TranslatableComponent src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject object = new JsonObject();
serialize( object, src, context );
object.addProperty( "translate", src.getTranslate() );
if ( src.getWith() != null )
{
object.add( "with", context.serialize( src.getWith() ) );
}
if ( src.getFallback() != null )
{
object.addProperty( "fallback", src.getFallback() );
}
return object;
}
}

View File

@@ -1,269 +0,0 @@
package net.md_5.bungee.chat;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
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.JsonParser;
import com.google.gson.JsonPrimitive;
import java.lang.reflect.Type;
import java.util.Set;
import lombok.Getter;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentStyle;
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.Content;
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;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
public class VersionedComponentSerializer implements JsonDeserializer<BaseComponent>
{
@Getter
@ApiStatus.Internal
private final Gson gson;
@Getter
@ApiStatus.Internal
private final ChatVersion version;
public VersionedComponentSerializer(ChatVersion version)
{
this.version = version;
this.gson = new GsonBuilder().
registerTypeAdapter( BaseComponent.class, this ).
registerTypeAdapter( TextComponent.class, new TextComponentSerializer( this ) ).
registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer( this ) ).
registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer( this ) ).
registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer( this ) ).
registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer( this ) ).
registerTypeAdapter( ComponentStyle.class, new ComponentStyleSerializer() ).
registerTypeAdapter( Entity.class, new EntitySerializer( this ) ).
registerTypeAdapter( Text.class, new TextSerializer() ).
registerTypeAdapter( Item.class, new ItemSerializer() ).
registerTypeAdapter( ItemTag.class, new ItemTag.Serializer() ).
create();
}
private static final VersionedComponentSerializer v1_16 = new VersionedComponentSerializer( ChatVersion.V1_16 );
private static final VersionedComponentSerializer v1_21_5 = new VersionedComponentSerializer( ChatVersion.V1_21_5 );
public static VersionedComponentSerializer forVersion(ChatVersion version)
{
switch ( version )
{
case V1_16:
return v1_16;
case V1_21_5:
return v1_21_5;
default:
throw new IllegalArgumentException( "Unknown version " + version );
}
}
@Deprecated
@ApiStatus.Internal
public static VersionedComponentSerializer getDefault()
{
return v1_16;
}
@ApiStatus.Internal
public static final ThreadLocal<Set<BaseComponent>> serializedComponents = new ThreadLocal<Set<BaseComponent>>();
/**
* Parse a JSON-compliant String as an array of base components. The input
* can be one of either an array of components, or a single component
* object. If the input is an array, each component will be parsed
* individually and returned in the order that they were parsed. If the
* input is a single component object, a single-valued array with the
* component will be returned.
* <p>
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it
* will parse only one component as opposed to an array of components which
* is non- standard behavior. This method is still appropriate for parsing
* multiple components at once, although such use case is rarely (if at all)
* exhibited in vanilla Minecraft.
*
* @param json the component json to parse
* @return an array of all parsed components
*/
public BaseComponent[] parse(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
if ( jsonElement.isJsonArray() )
{
return gson.fromJson( jsonElement, BaseComponent[].class );
} else
{
return new BaseComponent[]
{
gson.fromJson( jsonElement, BaseComponent.class )
};
}
}
/**
* Deserialize a JSON-compliant String as a single component.
*
* @param json the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component string is passed as input
*/
public BaseComponent deserialize(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
return deserialize( jsonElement );
}
/**
* Deserialize a JSON element as a single component.
*
* @param jsonElement the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component is passed as input
*/
public BaseComponent deserialize(JsonElement jsonElement)
{
if ( jsonElement instanceof JsonPrimitive )
{
JsonPrimitive primitive = (JsonPrimitive) jsonElement;
if ( primitive.isString() )
{
return new TextComponent( primitive.getAsString() );
}
} else if ( jsonElement instanceof JsonArray )
{
BaseComponent[] array = gson.fromJson( jsonElement, BaseComponent[].class );
return TextComponent.fromArray( array );
}
return gson.fromJson( jsonElement, BaseComponent.class );
}
/**
* Deserialize a JSON-compliant String as a component style.
*
* @param json the component style json to parse
* @return the deserialized component style
* @throws IllegalArgumentException if anything other than a valid JSON
* component style string is passed as input
*/
public ComponentStyle deserializeStyle(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
return deserializeStyle( jsonElement );
}
/**
* Deserialize a JSON element as a component style.
*
* @param jsonElement the component style json to parse
* @return the deserialized component style
* @throws IllegalArgumentException if anything other than a valid JSON
* component style is passed as input
*/
public ComponentStyle deserializeStyle(JsonElement jsonElement)
{
return gson.fromJson( jsonElement, ComponentStyle.class );
}
public JsonElement toJson(BaseComponent component)
{
return gson.toJsonTree( component );
}
public JsonElement toJson(ComponentStyle style)
{
return gson.toJsonTree( style );
}
/**
* @param object the object to serialize
* @return the JSON string representation of the object
* @deprecated Error-prone, be careful which object you input here
*/
@Deprecated
public String toString(Object object)
{
return gson.toJson( object );
}
/**
* @param content the content to serialize
* @return the JSON string representation of the object
* @deprecated for legacy internal use only
*/
@Deprecated
public String toString(Content content)
{
return gson.toJson( content );
}
public String toString(BaseComponent component)
{
return gson.toJson( component );
}
public String toString(BaseComponent... components)
{
if ( components.length == 1 )
{
return gson.toJson( components[0] );
} else
{
return gson.toJson( new TextComponent( components ) );
}
}
public String toString(ComponentStyle style)
{
return gson.toJson( style );
}
@Override
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
if ( json.isJsonPrimitive() )
{
return new TextComponent( json.getAsString() );
}
JsonObject object = json.getAsJsonObject();
if ( object.has( "translate" ) )
{
return context.deserialize( json, TranslatableComponent.class );
}
if ( object.has( "keybind" ) )
{
return context.deserialize( json, KeybindComponent.class );
}
if ( object.has( "score" ) )
{
return context.deserialize( json, ScoreComponent.class );
}
if ( object.has( "selector" ) )
{
return context.deserialize( json, SelectorComponent.class );
}
return context.deserialize( json, TextComponent.class );
}
}