Flectone LogoFlectonePulse

Форматирование

MessageContext, MessagePipeline и MessageFlag, добавление своих MiniMessage тегов и управление этапами форматирования

MessageContext это одно сообщение на пути к одному игроку. Внутри лежит исходный текст, отправитель, получатель, набор MiniMessage тегов и флаги, которые включают и выключают этапы форматирования

Пакет net.flectone.pulse.model.event.message.context
МетодВозвращаетЧто отдаёт
message()StringИсходный текст, ещё не отрисованный
sender()FEntityТого, кто отправил сообщение
receiver()FPlayerТого, кто его прочитает
uuid()UUIDОбщий идентификатор всех копий сообщения
tagResolver()TagResolverВсе теги, доступные при отрисовке
flags()Map<MessageFlag, Boolean>Флаги форматирования
isFlag(MessageFlag)booleanСостояние флага с учётом значения по умолчанию
base()MessageContextБазовый контекст, если текущий работает обёрткой

Создание и изменение

import net.flectone.pulse.model.event.message.context.MessageContext;

MessageContext context = MessageContext.builder()
        .sender(fPlayer)
        .receiver(receiver)
        .message("<display_name> <white>привет")
        .build();

Контекст неизменяем, поэтому методы with* и add* отдают копию

МетодЧто делает
withMessage(String)Отдаёт копию с другим текстом
withSender(FEntity)Отдаёт копию с другим отправителем
withReceiver(FPlayer)Отдаёт копию с другим получателем
withUuid(UUID)Отдаёт копию с другим идентификатором
addFlag(MessageFlag, boolean)Отдаёт копию с изменённым флагом
addFlags(MessageFlag[], boolean[])Отдаёт копию с несколькими изменёнными флагами
addTagResolver(TagResolver)Отдаёт копию с добавленным тегом поверх остальных
addTagResolvers(TagResolver...)Отдаёт копию с несколькими добавленными тегами
toBuilder()Открывает билдер, заполненный текущими значениями

Расширенные контексты

Некоторые модули носят с собой дополнительные данные. Такие контексты оборачивают обычный и отдают ему общие поля

КонтекстДополнительное поле
ComponentMessageContextМетод component() отдаёт готовый компонент для вставки
StringMessageContextМетод string() отдаёт произвольную строку
ModerationMessageContextМетод moderation() отдаёт наказание
ExternalModerationMessageContextМетод externalModeration() отдаёт наказание из другого плагина
VanishMessageContextМетод vanished() отдаёт признак скрытого отправителя
// свой контекст строится поверх базового
CoinMessageContext.builder()
        .base(MessageContext.builder()
                .sender(fPlayer)
                .receiver(receiver)
                .message(format)
                .build()
        )
        .percent(percent)
        .build();

Свой тег

Самое частое применение API это свой MiniMessage тег, который потом можно вставить в любой формат сообщения в файлах локализации

Подпишись на MessageFormattingEvent

Создай TagResolver со своим тегом

Добавь его в контекст через addTagResolver() и верни событие

import net.flectone.pulse.annotation.Pulse;
import net.flectone.pulse.listener.PulseListener;
import net.flectone.pulse.model.event.Event;
import net.flectone.pulse.model.event.message.MessageFormattingEvent;
import net.flectone.pulse.model.event.message.context.MessageContext;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;

public class BalanceTagListener implements PulseListener {

    @Pulse(priority = Event.Priority.NORMAL)
    public Event onFormatting(MessageFormattingEvent event) {
        MessageContext context = event.context();

        TagResolver balanceTag = TagResolver.resolver("balance", (argumentQueue, ctx) -> {
            double balance = getBalance(context.sender().uuid());
            return Tag.selfClosingInserting(Component.text(String.format("%.2f", balance)));
        });

        return event.withContext(context.addTagResolver(balanceTag));
    }

}

Теперь в любом формате локализации можно писать <balance>

format: "<display_name> <gray>[<balance>$]<white>: <message>"

Готовые резолверы

MessagePipeline умеет создавать резолверы за тебя

import net.flectone.pulse.pipeline.MessagePipeline;

MessagePipeline messagePipeline = flectonePulse.get(MessagePipeline.class);

// тег с готовым компонентом
TagResolver serverTag = messagePipeline.resolver("server", Component.text("survival"));

// вычисляемый тег
TagResolver timeTag = messagePipeline.resolver("time", (queue, ctx) ->
        Tag.selfClosingInserting(Component.text(LocalTime.now().toString()))
);

// один тег под несколькими именами
TagResolver aliases = messagePipeline.resolver(Set.of("money", "balance"), Component.text("100"));

MessagePipeline

Пакет net.flectone.pulse.pipeline

Превращает исходный текст в то, что увидит клиент

МетодВозвращаетЧто делает
build(MessageContext)ComponentОтрисовывает компонент
buildStandard(MessageContext)StringОтрисовывает обратно в MiniMessage текст
buildPlain(MessageContext)StringОтрисовывает текст без форматирования
buildLegacy(MessageContext)StringОтрисовывает текст со старыми цветовыми кодами
buildLegacy(FPlayer, String)Optional<String>Отрисовывает произвольную строку для игрока
buildJson(MessageContext)StringОтрисовывает JSON форму для протокола
messageComponent(FEntity, FPlayer, String)ComponentОтрисовывает вложенное сообщение
Component component = messagePipeline.build(MessageContext.builder()
        .sender(fPlayer)
        .receiver(receiver)
        .message("<rainbow>Привет, <display_name></rainbow>")
        .build()
);

messageSender.sendMessage(receiver, component, false);

Теги встроенных модулей

Перечисление MessagePipeline.ReplacementTag хранит все теги, которые вставляют встроенные модули. Имя тега в сообщении это имя константы в нижнем регистре

ГруппаТеги
Именаdisplay_name, player, nickname, prefix, suffix, constant
Статусыafk, mute, stream, server, world
Модерацияswear, delete
Объектыplayer_head, sprite, texture и их варианты с суффиксом _or
Остальноеanimation, condition, mention, online, toponline, padding, question, replacement, translation, fading, fcolor
// имя тега в сообщении
String tagName = MessagePipeline.ReplacementTag.DISPLAY_NAME.getTagName(); // display_name

// резолвер, который стирает тег, если твой модуль выключен
TagResolver empty = MessagePipeline.ReplacementTag.MENTION.emptyResolver();

Флаги

Пакет net.flectone.pulse.constant

MessageFlag включает и выключает отдельные этапы обработки для конкретного сообщения

import net.flectone.pulse.constant.MessageFlag;

// отключаем проверку на мат и кэширование для этого сообщения
MessageContext context = messageContext
        .addFlag(MessageFlag.SWEAR_MODULE, false)
        .addFlag(MessageFlag.USE_CACHE, false);

Основные флаги

ФлагПо умолчаниюЧто делает
PLAYER_MESSAGEfalseЗначение true говорит, что сообщение написал игрок, и включает полную обработку ввода
USE_CACHEtrueКэширует отрисованные сообщения
PLAYER_NAMEtrueОбрабатывает тег имени игрока
REMOVE_DISABLED_TAGStrueСтирает теги выключенных модулей
URL_PROCESSINGtrueИщет ссылки
ITEM_DETECTIONtrueИщет предметы в сообщении
LEGACY_COLOR_CONVERSIONtrueПоддерживает старые цветовые коды
COLOR_CONTEXT_SENDERtrueБерёт цвета у отправителя, иначе у получателя
PLACEHOLDER_CONTEXT_SENDERtrueСчитает плейсхолдеры от отправителя, иначе от получателя
INVISIBLE_NAME_DETECTIONtrueПроверяет невидимость игрока, чтобы скрывать ник
INTERACTIVE_CHAT_COMPATtrueДаёт совместимость с InteractiveChat
VIOLATION_PROCESSINGtrueУчитывает нарушения в системе модерации

Флаги модулей

Выключенный флаг пропускает свой модуль форматирования

CAPS_MODULE, DELETE_MODULE, FIXATION_MODULE, FLOOD_MODULE, ICU_MODULE, MENTION_MODULE, NICKNAME_MODULE, PADDING_MODULE, QUESTIONANSWER_MODULE, REPLACEMENT_MODULE, SWEAR_MODULE, TRANSLATE_MODULE

Флаги объектов

OBJECT_DEFAULT_VALUE, OBJECT_PLAYER_HEAD_PROCESSING, OBJECT_SPRITE_PROCESSING, OBJECT_TEXTURE_PROCESSING, OBJECT_RECEIVER_VALIDATION

Предупреждение

Если флаг PLAYER_MESSAGE стоит в true, то флаг ICU_MODULE тоже считается включённым, каким бы ни было его собственное значение


Правка текста

@Pulse(priority = Event.Priority.HIGH)
public Event onFormatting(MessageFormattingEvent event) {
    MessageContext context = event.context();

    // трогаем только сообщения, написанные игроками
    if (!context.isFlag(MessageFlag.PLAYER_MESSAGE)) return event;

    String message = context.message();
    if (!message.contains("реклама")) return event;

    // отменяем сообщение целиком
    return event.withCancelled(true);
}

Оформление компонентов

ComponentDecorator помогает добавить подсказку или декорацию для всего компонента и дочерних компнентов, не затирая уже существующие стили

Пакет net.flectone.pulse.decorator
МетодЧто делает
hover(Component, HoverEvent)Добавляет всплывающую подсказку
hoverIfAbsent(Component, HoverEvent)Добавляет подсказку, только если её ещё нет
decorate(Component, TextDecoration, State)Применяет декорацию, например жирный или курсив
decorateIfAbsent(Component, TextDecoration, State)Применяет декорацию, только если она не задана
Примечание

Форматирование идёт для каждого получателя отдельно, помни об этом при тяжёлых вычислениях внутри резолвера. Кэш включён по умолчанию, поэтому для быстро меняющихся данных выключай флаг USE_CACHE. Синтаксис самих тегов описан на странице форматирования сообщений

Последнее изменение 11 августа 2026 г.
Редактировать на GitHub

На этой странице