All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.kyori.text.serializer.LegacyComponentSerializerImpl Maven / Gradle / Ivy

There is a newer version: 1.12-1.6.5
Show newest version
/*
 * 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