#3874: Add ObjectComponents
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.chat.objects.ChatObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object component that can be used to display objects.
|
||||||
|
* <p>
|
||||||
|
* It can either display a player's head or an object by a specific sprite and
|
||||||
|
* an atlas.
|
||||||
|
* <p>
|
||||||
|
* Note: this was added in Minecraft 1.21.9.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public final class ObjectComponent extends BaseComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
private ChatObject object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ObjectComponent from a given ChatObject.
|
||||||
|
*
|
||||||
|
* See {@link net.md_5.bungee.api.chat.objects.PlayerObject} and
|
||||||
|
* {@link net.md_5.bungee.api.chat.objects.SpriteObject}.
|
||||||
|
*
|
||||||
|
* @param object the ChatObject
|
||||||
|
*/
|
||||||
|
public ObjectComponent(@NonNull ChatObject object)
|
||||||
|
{
|
||||||
|
this.object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an object component from the original to clone it.
|
||||||
|
*
|
||||||
|
* @param original the original for the new score component
|
||||||
|
*/
|
||||||
|
public ObjectComponent(ObjectComponent original)
|
||||||
|
{
|
||||||
|
super( original );
|
||||||
|
setObject( original.object );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectComponent duplicate()
|
||||||
|
{
|
||||||
|
return new ObjectComponent( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toPlainText(StringVisitor builder)
|
||||||
|
{
|
||||||
|
// I guess we cannot convert this to plain text
|
||||||
|
// builder.append( this.value );
|
||||||
|
super.toPlainText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toLegacyText(StringVisitor builder)
|
||||||
|
{
|
||||||
|
addFormat( builder );
|
||||||
|
// Same here...
|
||||||
|
// builder.append( this.value );
|
||||||
|
super.toLegacyText( builder );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
package net.md_5.bungee.api.chat.objects;
|
||||||
|
|
||||||
|
public interface ChatObject
|
||||||
|
{
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
package net.md_5.bungee.api.chat.objects;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import net.md_5.bungee.api.chat.player.Profile;
|
||||||
|
import net.md_5.bungee.api.chat.player.Property;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public final class PlayerObject implements ChatObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The profile of the player.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private Profile profile;
|
||||||
|
/**
|
||||||
|
* If true, a hat layer will be rendered on the head. (default: true)
|
||||||
|
*/
|
||||||
|
private Boolean hat;
|
||||||
|
|
||||||
|
public PlayerObject(@NonNull String name)
|
||||||
|
{
|
||||||
|
this.profile = new Profile( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerObject(@NonNull UUID uuid)
|
||||||
|
{
|
||||||
|
this.profile = new Profile( uuid );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerObject(@NonNull Property[] properties)
|
||||||
|
{
|
||||||
|
this.profile = new Profile( properties );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
package net.md_5.bungee.api.chat.objects;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public final class SpriteObject implements ChatObject
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The namespaced ID of a sprite atlas, default value: minecraft:blocks.
|
||||||
|
*/
|
||||||
|
private String atlas;
|
||||||
|
/**
|
||||||
|
* The namespaced ID of a sprite in atlas, for example item/porkchop.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private String sprite;
|
||||||
|
}
|
@@ -0,0 +1,40 @@
|
|||||||
|
package net.md_5.bungee.api.chat.player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Profile
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the profile. Can be null.
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* The UUID of the profile. Can be null.
|
||||||
|
*/
|
||||||
|
private UUID uuid;
|
||||||
|
/**
|
||||||
|
* The properties of the profile. Can be null.
|
||||||
|
*/
|
||||||
|
private Property[] properties;
|
||||||
|
|
||||||
|
public Profile(@NonNull String name)
|
||||||
|
{
|
||||||
|
this( name, null, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile(@NonNull UUID uuid)
|
||||||
|
{
|
||||||
|
this( null, uuid, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile(@NonNull Property[] properties)
|
||||||
|
{
|
||||||
|
this( null, null, properties );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
package net.md_5.bungee.api.chat.player;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Property
|
||||||
|
{
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private String name;
|
||||||
|
@NonNull
|
||||||
|
private String value;
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
public Property(@NonNull String name, @NonNull String value)
|
||||||
|
{
|
||||||
|
this( name, value, null );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,138 @@
|
|||||||
|
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.UUID;
|
||||||
|
import net.md_5.bungee.api.chat.ObjectComponent;
|
||||||
|
import net.md_5.bungee.api.chat.objects.PlayerObject;
|
||||||
|
import net.md_5.bungee.api.chat.objects.SpriteObject;
|
||||||
|
import net.md_5.bungee.api.chat.player.Profile;
|
||||||
|
import net.md_5.bungee.api.chat.player.Property;
|
||||||
|
|
||||||
|
public class ObjectComponentSerializer extends BaseComponentSerializer implements JsonSerializer<ObjectComponent>, JsonDeserializer<ObjectComponent>
|
||||||
|
{
|
||||||
|
|
||||||
|
public ObjectComponentSerializer(VersionedComponentSerializer serializer)
|
||||||
|
{
|
||||||
|
super( serializer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||||
|
{
|
||||||
|
JsonObject object = json.getAsJsonObject();
|
||||||
|
|
||||||
|
String sprite = object.has( "sprite" ) ? object.get( "sprite" ).getAsString() : null;
|
||||||
|
String atlas = object.has( "atlas" ) ? object.get( "atlas" ).getAsString() : null;
|
||||||
|
|
||||||
|
if ( sprite != null )
|
||||||
|
{
|
||||||
|
ObjectComponent component = new ObjectComponent( new SpriteObject( atlas, sprite ) );
|
||||||
|
deserialize( object, component, context );
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
JsonElement player = object.get( "player" );
|
||||||
|
if ( player != null )
|
||||||
|
{
|
||||||
|
String name = null;
|
||||||
|
UUID uuid = null;
|
||||||
|
Property[] properties = null;
|
||||||
|
Boolean hat = object.has( "hat" ) ? object.get( "hat" ).getAsBoolean() : null;
|
||||||
|
if ( player.isJsonObject() )
|
||||||
|
{
|
||||||
|
JsonObject playerObj = player.getAsJsonObject();
|
||||||
|
validateName( name = playerObj.has( "name" ) ? playerObj.get( "name" ).getAsString() : null );
|
||||||
|
uuid = playerObj.has( "id" ) ? parseUUID( context.deserialize( playerObj.get( "id" ), int[].class ) ) : null;
|
||||||
|
properties = playerObj.has( "properties" ) ? context.deserialize( playerObj.get( "properties" ), Property[].class ) : null;
|
||||||
|
} else if ( player.isJsonPrimitive() )
|
||||||
|
{
|
||||||
|
validateName( name = player.getAsString() );
|
||||||
|
}
|
||||||
|
ObjectComponent component = new ObjectComponent( new PlayerObject( new Profile( name, uuid, properties ), hat ) );
|
||||||
|
deserialize( object, component, context );
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new JsonParseException( "Could not parse JSON: missing 'player' or 'sprite' property" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(ObjectComponent src, Type typeOfSrc, JsonSerializationContext context)
|
||||||
|
{
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
serialize( object, src, context );
|
||||||
|
|
||||||
|
if ( src.getObject() instanceof SpriteObject )
|
||||||
|
{
|
||||||
|
SpriteObject sprite = (SpriteObject) src.getObject();
|
||||||
|
object.addProperty( "sprite", sprite.getSprite() );
|
||||||
|
if ( sprite.getAtlas() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "atlas", sprite.getAtlas() );
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( src.getObject() instanceof PlayerObject )
|
||||||
|
{
|
||||||
|
PlayerObject player = (PlayerObject) src.getObject();
|
||||||
|
|
||||||
|
if ( player.getHat() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "hat", player.getHat() );
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject playerObj = new JsonObject();
|
||||||
|
Profile profile = player.getProfile();
|
||||||
|
|
||||||
|
if ( profile.getName() != null )
|
||||||
|
{
|
||||||
|
playerObj.addProperty( "name", profile.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( profile.getUuid() != null )
|
||||||
|
{
|
||||||
|
int[] uuidArray = new int[4];
|
||||||
|
long most = profile.getUuid().getMostSignificantBits();
|
||||||
|
long least = profile.getUuid().getLeastSignificantBits();
|
||||||
|
uuidArray[0] = (int) ( most >> 32 );
|
||||||
|
uuidArray[1] = (int) most;
|
||||||
|
uuidArray[2] = (int) ( least >> 32 );
|
||||||
|
uuidArray[3] = (int) least;
|
||||||
|
playerObj.add( "id", context.serialize( uuidArray ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( profile.getProperties() != null )
|
||||||
|
{
|
||||||
|
playerObj.add( "properties", context.serialize( profile.getProperties(), Property[].class ) );
|
||||||
|
}
|
||||||
|
object.add( "player", playerObj );
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new JsonParseException( "Could not serialize ObjectComponent: unknown object type " + src.getObject().getClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UUID parseUUID(int[] array)
|
||||||
|
{
|
||||||
|
if ( array.length != 4 )
|
||||||
|
{
|
||||||
|
throw new JsonParseException( "UUID integer array must be exactly 4 integers long" );
|
||||||
|
}
|
||||||
|
return new UUID( (long) array[0] << 32 | (long) array[1] & 0XFFFFFFFFL, (long) array[2] << 32 | (long) array[3] & 0XFFFFFFFFL );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void validateName(String name)
|
||||||
|
{
|
||||||
|
if ( name != null && ( name.length() > 16 || name.isEmpty() ) )
|
||||||
|
{
|
||||||
|
throw new JsonParseException( "Could not parse JSON: player name must be 16 characters or fewer and not empty" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
|
|||||||
import net.md_5.bungee.api.chat.ComponentStyle;
|
import net.md_5.bungee.api.chat.ComponentStyle;
|
||||||
import net.md_5.bungee.api.chat.ItemTag;
|
import net.md_5.bungee.api.chat.ItemTag;
|
||||||
import net.md_5.bungee.api.chat.KeybindComponent;
|
import net.md_5.bungee.api.chat.KeybindComponent;
|
||||||
|
import net.md_5.bungee.api.chat.ObjectComponent;
|
||||||
import net.md_5.bungee.api.chat.ScoreComponent;
|
import net.md_5.bungee.api.chat.ScoreComponent;
|
||||||
import net.md_5.bungee.api.chat.SelectorComponent;
|
import net.md_5.bungee.api.chat.SelectorComponent;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
@@ -61,6 +62,7 @@ public class VersionedComponentSerializer implements JsonDeserializer<BaseCompon
|
|||||||
registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer( this ) ).
|
registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer( this ) ).
|
||||||
registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer( this ) ).
|
registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer( this ) ).
|
||||||
registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer( this ) ).
|
registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer( this ) ).
|
||||||
|
registerTypeAdapter( ObjectComponent.class, new ObjectComponentSerializer( this ) ).
|
||||||
registerTypeAdapter( ComponentStyle.class, new ComponentStyleSerializer() ).
|
registerTypeAdapter( ComponentStyle.class, new ComponentStyleSerializer() ).
|
||||||
registerTypeAdapter( Entity.class, new EntitySerializer( this ) ).
|
registerTypeAdapter( Entity.class, new EntitySerializer( this ) ).
|
||||||
registerTypeAdapter( Text.class, new TextSerializer() ).
|
registerTypeAdapter( Text.class, new TextSerializer() ).
|
||||||
@@ -290,6 +292,10 @@ public class VersionedComponentSerializer implements JsonDeserializer<BaseCompon
|
|||||||
{
|
{
|
||||||
return context.deserialize( json, SelectorComponent.class );
|
return context.deserialize( json, SelectorComponent.class );
|
||||||
}
|
}
|
||||||
|
if ( object.has( "player" ) || object.has( "sprite" ) )
|
||||||
|
{
|
||||||
|
return context.deserialize( json, ObjectComponent.class );
|
||||||
|
}
|
||||||
return context.deserialize( json, TextComponent.class );
|
return context.deserialize( json, TextComponent.class );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user