#2342: Add score and selector components to chat API

This commit is contained in:
Senmori
2018-02-19 11:47:21 +11:00
committed by md_5
parent e23195f5f2
commit a3b44aa612
11 changed files with 420 additions and 7 deletions

View File

@@ -35,7 +35,7 @@ public final class KeybindComponent extends BaseComponent
* Creates a keybind component with the passed internal keybind value.
*
* @param keybind the keybind value
* @see Keybind
* @see Keybinds
*/
public KeybindComponent(String keybind)
{

View File

@@ -0,0 +1,97 @@
package net.md_5.bungee.api.chat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* This component displays the score based on a player score on the scoreboard.
* <br>
* The <b>name</b> is the name of the player stored on the scoreboard, which may
* be a "fake" player. It can also be a target selector that <b>must</b> resolve
* to 1 target, and may target non-player entities.
* <br>
* With a book, /tellraw, or /title, using the wildcard '*' in the place of a
* name or target selector will cause all players to see their own score in the
* specified objective.
* <br>
* <b>Signs cannot use the '*' wildcard</b>
* <br>
* These values are filled in by the server-side implementation.
* <br>
* As of 1.12.2, a bug ( MC-56373 ) prevents full usage within hover events.
*/
@Getter
@Setter
@ToString
@AllArgsConstructor
public final class ScoreComponent extends BaseComponent
{
/**
* The name of the entity whose score should be displayed.
*/
private String name;
/**
* The internal name of the objective the score is attached to.
*/
private String objective;
/**
* The optional value to use instead of the one present in the Scoreboard.
*/
private String value = "";
/**
* Creates a new score component with the specified name and objective.<br>
* If not specifically set, value will default to an empty string;
* signifying that the scoreboard value should take precedence. If not null,
* nor empty, {@code value} will override any value found in the
* scoreboard.<br>
* The value defaults to an empty string.
*
* @param name the name of the entity, or an entity selector, whose score
* should be displayed
* @param objective the internal name of the objective the entity's score is
* attached to
*/
public ScoreComponent(String name, String objective)
{
setName( name );
setObjective( objective );
}
/**
* Creates a score component from the original to clone it.
*
* @param original the original for the new score component
*/
public ScoreComponent(ScoreComponent original)
{
super( original );
setName( original.getName() );
setObjective( original.getObjective() );
setValue( original.getValue() );
}
@Override
public ScoreComponent duplicate()
{
return new ScoreComponent( this );
}
@Override
public ScoreComponent duplicateWithoutFormatting()
{
return new ScoreComponent( this.name, this.objective, this.value );
}
@Override
protected void toLegacyText(StringBuilder builder)
{
builder.append( this.value );
super.toLegacyText( builder );
}
}

View File

@@ -0,0 +1,63 @@
package net.md_5.bungee.api.chat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* This component processes a target selector into a pre-formatted set of
* discovered names.
* <br>
* Multiple targets may be obtained, and with commas separating each one and a
* final "and" for the last target. The resulting format cannot be overwritten.
* This includes all styling from team prefixes, insertions, click events, and
* hover events.
* <br>
* These values are filled in by the server-side implementation.
* <br>
* As of 1.12.2, a bug ( MC-56373 ) prevents full usage within hover events.
*/
@Getter
@Setter
@ToString
@AllArgsConstructor
public final class SelectorComponent extends BaseComponent
{
/**
* An entity target selector (@p, @a, @r, @e, or @s) and, optionally,
* selector arguments (e.g. @e[r=10,type=Creeper]).
*/
private String selector;
/**
* Creates a selector component from the original to clone it.
*
* @param original the original for the new selector component
*/
public SelectorComponent(SelectorComponent original)
{
super( original );
setSelector( original.getSelector() );
}
@Override
public SelectorComponent duplicate()
{
return new SelectorComponent( this );
}
@Override
public SelectorComponent duplicateWithoutFormatting()
{
return new SelectorComponent( this.selector );
}
@Override
protected void toLegacyText(StringBuilder builder)
{
builder.append( this.selector );
super.toLegacyText( builder );
}
}

View File

@@ -9,6 +9,8 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import net.md_5.bungee.api.chat.BaseComponent;
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;
@@ -23,6 +25,8 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ).
registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ).
registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ).
registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ).
create();
public final static ThreadLocal<HashSet<BaseComponent>> serializedComponents = new ThreadLocal<HashSet<BaseComponent>>();
@@ -65,6 +69,14 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
{
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 );
}
}

View File

@@ -0,0 +1,49 @@
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>
{
@Override
public ScoreComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{
JsonObject json = element.getAsJsonObject();
if ( !json.has( "name" ) || !json.has( "objective" ) )
{
throw new JsonParseException( "A score component needs at least a name and an objective" );
}
String name = json.get( "name" ).getAsString();
String objective = json.get( "objective" ).getAsString();
ScoreComponent component = new ScoreComponent( name, objective );
if ( json.has( "value" ) && !json.get( "value" ).getAsString().isEmpty() )
{
component.setValue( json.get( "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

@@ -0,0 +1,33 @@
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>
{
@Override
public SelectorComponent deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
{
JsonObject object = element.getAsJsonObject();
SelectorComponent component = new SelectorComponent( object.get( "selector" ).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() );
return object;
}
}