001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.configuration.caption; 020 021import com.plotsquared.core.configuration.Settings; 022import com.plotsquared.core.player.PlotPlayer; 023import com.plotsquared.core.plot.flag.PlotFlag; 024import com.plotsquared.core.plot.flag.implementations.DescriptionFlag; 025import com.plotsquared.core.plot.flag.implementations.FarewellFlag; 026import com.plotsquared.core.plot.flag.implementations.GreetingFlag; 027import com.plotsquared.core.plot.flag.implementations.PlotTitleFlag; 028import net.kyori.adventure.text.Component; 029import net.kyori.adventure.text.event.ClickEvent; 030import net.kyori.adventure.text.minimessage.MiniMessage; 031import net.kyori.adventure.text.minimessage.ParsingException; 032import org.checkerframework.checker.nullness.qual.NonNull; 033import org.checkerframework.checker.nullness.qual.Nullable; 034 035import java.util.Objects; 036import java.util.Set; 037import java.util.regex.Pattern; 038import java.util.stream.Collectors; 039 040import static com.plotsquared.core.configuration.caption.ComponentTransform.nested; 041 042public class CaptionUtility { 043 044 private static final Pattern LEGACY_FORMATTING = Pattern.compile("ยง[a-gklmnor0-9]"); 045 046 // flags which values are parsed by minimessage 047 private static final Set<Class<? extends PlotFlag<?, ?>>> MINI_MESSAGE_FLAGS = Set.of( 048 GreetingFlag.class, 049 FarewellFlag.class, 050 DescriptionFlag.class, 051 PlotTitleFlag.class 052 ); 053 054 private static final ComponentTransform CLICK_STRIP_TRANSFORM = nested( 055 new ClickStripTransform( 056 Settings.Chat.CLICK_EVENT_ACTIONS_TO_REMOVE.stream() 057 .map(ClickEvent.Action.NAMES::value) 058 .filter(Objects::nonNull) 059 .collect(Collectors.toUnmodifiableSet()) 060 ) 061 ); 062 063 064 /** 065 * Format a chat message but keep the formatting keys 066 * 067 * @param recipient Message recipient 068 * @param message Message 069 * @return Formatted message 070 */ 071 public static String formatRaw(PlotPlayer<?> recipient, String message) { 072 final ChatFormatter.ChatContext chatContext = 073 new ChatFormatter.ChatContext(recipient, message, true); 074 for (final ChatFormatter chatFormatter : ChatFormatter.formatters) { 075 chatFormatter.format(chatContext); 076 } 077 return chatContext.getMessage(); 078 } 079 080 /** 081 * Format a chat message 082 * 083 * @param recipient Message recipient 084 * @param message Message 085 * @return Formatted message 086 */ 087 public static String format( 088 final @Nullable PlotPlayer<?> recipient, 089 final @NonNull String message 090 ) { 091 final ChatFormatter.ChatContext chatContext = 092 new ChatFormatter.ChatContext(recipient, message, false); 093 for (final ChatFormatter chatFormatter : ChatFormatter.formatters) { 094 chatFormatter.format(chatContext); 095 } 096 return chatContext.getMessage(); 097 } 098 099 /** 100 * Strips configured click events from a MiniMessage string. 101 * 102 * @param miniMessageString the message from which the specified click events should be removed from. 103 * @return the string without the click events that are configured to be removed. 104 * @see Settings.Chat#CLICK_EVENT_ACTIONS_TO_REMOVE 105 * @since 6.0.10 106 */ 107 public static String stripClickEvents(final @NonNull String miniMessageString) { 108 // parse, transform and serialize again 109 Component component; 110 try { 111 component = MiniMessage.miniMessage().deserialize(miniMessageString); 112 } catch (ParsingException e) { 113 // if the String cannot be parsed, we try stripping legacy colors 114 String legacyStripped = LEGACY_FORMATTING.matcher(miniMessageString).replaceAll(""); 115 component = MiniMessage.miniMessage().deserialize(legacyStripped); 116 } 117 component = CLICK_STRIP_TRANSFORM.transform(component); 118 return MiniMessage.miniMessage().serialize(component); 119 } 120 121 /** 122 * Strips configured MiniMessage click events from a plot flag value. 123 * This is used before letting the string be parsed by the plot flag. 124 * This method works the same way as {@link #stripClickEvents(String)} but will only 125 * strip click events from messages that target flags that are meant to contain MiniMessage strings. 126 * 127 * @param flag the flag the message is targeted for. 128 * @param miniMessageString the message from which the specified click events should be removed from. 129 * @return the string without the click events that are configured to be removed. 130 * @see Settings.Chat#CLICK_EVENT_ACTIONS_TO_REMOVE 131 * @see #stripClickEvents(String) 132 * @since 6.0.10 133 */ 134 public static String stripClickEvents( 135 final @NonNull PlotFlag<?, ?> flag, 136 final @NonNull String miniMessageString 137 ) { 138 if (MINI_MESSAGE_FLAGS.contains(flag.getClass())) { 139 return stripClickEvents(miniMessageString); 140 } 141 return miniMessageString; 142 } 143 144}