net.kyori.text.serializer.LegacyComponentSerializerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of text Show documentation
Show all versions of text Show documentation
A text library for Minecraft.
/*
* This file is part of text, licensed under the MIT License.
*
* Copyright (c) 2017 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.kyori.text.serializer;
import com.google.common.collect.Streams;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
import net.kyori.text.format.TextDecoration;
import net.kyori.text.format.TextFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Deprecated
class LegacyComponentSerializerImpl implements LegacyComponentSerializer {
private static final TextDecoration[] DECORATIONS = TextDecoration.values();
private static final TextFormat[] FORMATS = Streams.concat(Arrays.stream(TextColor.values()), Arrays.stream(DECORATIONS), Stream.of(Reset.INSTANCE)).toArray(TextFormat[]::new);
private static final String FORMAT_LOOKUP = Arrays.stream(FORMATS).map(format -> String.valueOf(format.legacy())).collect(Collectors.joining());
@Nonnull
@Override
public TextComponent deserialize(@Nonnull String input, char character) {
int next = input.lastIndexOf(character, input.length() - 2);
if(next == -1) {
return TextComponent.of(input);
}
final List parts = new ArrayList<>();
TextComponent.Builder current = null;
boolean reset = false;
int pos = input.length();
do {
final TextFormat format = find(input.charAt(next + 1));
if(format != null) {
final int from = next + 2;
if(from != pos) {
if(current != null) {
if(reset) {
parts.add(current.build());
reset = false;
current = TextComponent.builder("");
} else {
current = TextComponent.builder("").append(current.build());
}
} else {
current = TextComponent.builder("");
}
current.content(input.substring(from, pos));
} else if(current == null) {
current = TextComponent.builder("");
}
reset |= applyFormat(current, format);
pos = next;
}
next = input.lastIndexOf(character, next - 1);
} while(next != -1);
if(current != null) {
parts.add(current.build());
}
Collections.reverse(parts);
return TextComponent.builder(pos > 0 ? input.substring(0, pos) : "").append(parts).build();
}
@Nonnull
@Override
public String serialize(@Nonnull Component component, final char character) {
final Cereal state = new Cereal(character);
state.append(component);
return state.toString();
}
private static boolean applyFormat(@Nonnull final TextComponent.Builder builder, @Nonnull final TextFormat format) {
if(format instanceof TextColor) {
builder.color((TextColor) format);
return true;
} else if(format instanceof TextDecoration) {
builder.decoration((TextDecoration) format, TextDecoration.State.TRUE);
return false;
} else if(format instanceof Reset) {
builder.color(null);
for(final TextDecoration decoration : DECORATIONS) {
builder.decoration(decoration, TextDecoration.State.NOT_SET);
}
return true;
}
throw new IllegalArgumentException(String.format("unknown format '%s'", format.getClass()));
}
private static TextFormat find(final char legacy) {
final int pos = FORMAT_LOOKUP.indexOf(legacy);
return pos == -1 ? null : FORMATS[pos];
}
@Deprecated
private enum Reset implements TextFormat {
INSTANCE;
@Deprecated
@Override
public char legacy() {
return 'r';
}
}
// Are you hungry?
@Deprecated
private static final class Cereal {
private final StringBuilder sb = new StringBuilder();
private final Style style = new Style();
private final char character;
Cereal(final char character) {
this.character = character;
}
void append(@Nonnull final Component component) {
this.append(component, new Style());
}
private void append(@Nonnull final Component component, @Nonnull final Style style) {
style.apply(component);
if(component instanceof TextComponent) {
final String content = ((TextComponent) component).content();
if(!content.isEmpty()) {
style.applyFormat();
this.sb.append(content);
}
}
final List children = component.children();
if(!children.isEmpty()) {
final Style childrenStyle = new Style(style);
for(final Component child : component.children()) {
this.append(child, childrenStyle);
childrenStyle.set(style);
}
}
}
private void append(@Nonnull final TextFormat format) {
this.sb.append(this.character).append(format.legacy());
}
@Override
public String toString() {
return this.sb.toString();
}
private final class Style {
@Nullable private TextColor color;
private final Set decorations;
Style() {
this.decorations = EnumSet.noneOf(TextDecoration.class);
}
Style(@Nonnull final Style that) {
this.color = that.color;
this.decorations = EnumSet.copyOf(that.decorations);
}
void set(@Nonnull final Style that) {
this.color = that.color;
this.decorations.clear();
this.decorations.addAll(that.decorations);
}
void apply(@Nonnull final Component component) {
if(component.color() != null) {
this.color = component.color();
}
for(final TextDecoration decoration : DECORATIONS) {
switch(component.decoration(decoration)) {
case TRUE:
this.decorations.add(decoration);
break;
case FALSE:
this.decorations.remove(decoration);
break;
}
}
}
void applyFormat() {
// If color changes, we need to do a full reset
if(this.color != Cereal.this.style.color) {
this.applyFullFormat();
return;
}
// Does current have any decorations we don't have?
// Since there is no way to undo decorations, we need to reset these cases
if(!this.decorations.containsAll(Cereal.this.style.decorations)) {
this.applyFullFormat();
return;
}
// Apply new decorations
for(final TextDecoration decoration : this.decorations) {
if(Cereal.this.style.decorations.add(decoration)) {
Cereal.this.append(decoration);
}
}
}
private void applyFullFormat() {
if(this.color != null) {
Cereal.this.append(this.color);
Cereal.this.style.color = this.color;
} else {
Cereal.this.append(Reset.INSTANCE);
}
for(final TextDecoration decoration : this.decorations) {
Cereal.this.append(decoration);
}
Cereal.this.style.decorations.clear();
Cereal.this.style.decorations.addAll(this.decorations);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy