Add config options for specific chat type formats

This commit is contained in:
Flowsqy 2023-05-05 19:29:54 +02:00 committed by Josh Roy
parent c7cc1b4f93
commit 2a41ea050a
5 changed files with 153 additions and 31 deletions

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.signs.EssentialsSign;
import com.earth2me.essentials.textreader.IText;
import net.essentialsx.api.v2.ChatType;
import net.kyori.adventure.text.minimessage.tag.Tag;
import org.bukkit.Material;
import org.bukkit.event.EventPriority;
@ -37,6 +38,8 @@ public interface ISettings extends IConf {
String getChatFormat(String group);
String getChatFormat(String group, ChatType chatType);
String getWorldAlias(String world);
int getChatRadius();

View File

@ -14,6 +14,7 @@ import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IEssentials;
import net.essentialsx.api.v2.ChatType;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.tag.Tag;
@ -35,6 +36,7 @@ import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@ -45,6 +47,7 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@ -59,7 +62,7 @@ public class Settings implements net.ess3.api.ISettings {
private final transient EssentialsConfiguration config;
private final transient IEssentials ess;
private final transient AtomicInteger reloadCount = new AtomicInteger(0);
private final Map<String, String> chatFormats = Collections.synchronizedMap(new HashMap<>());
private final ChatFormats chatFormats = new ChatFormats();
private int chatRadius = 0;
// #easteregg
private char chatShout = '!';
@ -199,7 +202,7 @@ public class Settings implements net.ess3.api.ISettings {
final Set<String> homeList = getMultipleHomes();
if (homeList != null) {
for (final String set : homeList) {
if (user.isAuthorized("essentials.sethome.multiple." + set) && (limit < getHomeLimit(set))) {
if (user.isAuthorized("essentials.sethome.multiple." + set) && limit < getHomeLimit(set)) {
limit = getHomeLimit(set);
}
}
@ -590,32 +593,132 @@ public class Settings implements net.ess3.api.ISettings {
@Override
public String getChatFormat(final String group) {
String mFormat = chatFormats.get(group);
if (mFormat == null) {
mFormat = config.getString("chat.group-formats." + (group == null ? "Default" : group), config.getString("chat.format", "&7[{GROUP}]&r {DISPLAYNAME}&7:&r {MESSAGE}"));
mFormat = FormatUtil.replaceFormat(mFormat);
mFormat = mFormat.replace("{DISPLAYNAME}", "%1$s");
mFormat = mFormat.replace("{MESSAGE}", "%2$s");
mFormat = mFormat.replace("{GROUP}", "{0}");
mFormat = mFormat.replace("{WORLD}", "{1}");
mFormat = mFormat.replace("{WORLDNAME}", "{1}");
mFormat = mFormat.replace("{SHORTWORLDNAME}", "{2}");
mFormat = mFormat.replace("{TEAMPREFIX}", "{3}");
mFormat = mFormat.replace("{TEAMSUFFIX}", "{4}");
mFormat = mFormat.replace("{TEAMNAME}", "{5}");
mFormat = mFormat.replace("{PREFIX}", "{6}");
mFormat = mFormat.replace("{SUFFIX}", "{7}");
mFormat = mFormat.replace("{USERNAME}", "{8}");
mFormat = mFormat.replace("{NICKNAME}", "{9}");
mFormat = "§r".concat(mFormat);
chatFormats.put(group, mFormat);
}
return getChatFormat(group, null);
}
@Override
public String getChatFormat(final String group, final ChatType chatType) {
final String mFormat = chatFormats.getFormat(group, chatType, new ChatFormatConfigSupplier(group, chatType));
if (isDebug()) {
ess.getLogger().info(String.format("Found format '%s' for group '%s'", mFormat, group));
}
return mFormat;
}
private class ChatFormatConfigSupplier implements Supplier<String> {
private final String group;
private final ChatType chatType;
ChatFormatConfigSupplier(String group, ChatType chatType) {
this.group = group;
this.chatType = chatType;
}
@Override
public String get() {
final String chatKey = chatType.key();
final String groupPath = "chat.group-formats." + (group == null ? "Default" : group);
String configFormat = config.getString(groupPath + "." + chatKey, null);
if (configFormat == null) {
configFormat = config.getString(groupPath, null);
}
final String formatPath = "chat.format";
if (configFormat == null) {
configFormat = config.getString(formatPath + "." + chatKey, null);
}
if (configFormat == null) {
configFormat = config.getString(formatPath, null);
}
if (configFormat == null) {
configFormat = "&7[{GROUP}]&r {DISPLAYNAME}&7:&r {MESSAGE}";
}
configFormat = FormatUtil.replaceFormat(configFormat);
configFormat = configFormat.replace("{DISPLAYNAME}", "%1$s");
configFormat = configFormat.replace("{MESSAGE}", "%2$s");
configFormat = configFormat.replace("{GROUP}", "{0}");
configFormat = configFormat.replace("{WORLD}", "{1}");
configFormat = configFormat.replace("{WORLDNAME}", "{1}");
configFormat = configFormat.replace("{SHORTWORLDNAME}", "{2}");
configFormat = configFormat.replace("{TEAMPREFIX}", "{3}");
configFormat = configFormat.replace("{TEAMSUFFIX}", "{4}");
configFormat = configFormat.replace("{TEAMNAME}", "{5}");
configFormat = configFormat.replace("{PREFIX}", "{6}");
configFormat = configFormat.replace("{SUFFIX}", "{7}");
configFormat = configFormat.replace("{USERNAME}", "{8}");
configFormat = configFormat.replace("{NICKNAME}", "{9}");
configFormat = "§r".concat(configFormat);
return configFormat;
}
}
private static class ChatFormats {
private final Map<String, TypedChatFormat> groupFormats;
private TypedChatFormat defaultFormat;
ChatFormats() {
defaultFormat = null;
groupFormats = new HashMap<>();
}
public String getFormat(String group, ChatType type, Supplier<String> configSupplier) {
// With such a large synchronize block, we synchronize a potential config deserialization
// It does not matter as it needs to be done. It's even better as we ensure to do it once
// TypedChatFormat is also synchronized
synchronized (this) {
final TypedChatFormat typedChatFormat;
if (group == null) {
if (defaultFormat == null) {
defaultFormat = new TypedChatFormat();
}
typedChatFormat = defaultFormat;
} else {
typedChatFormat = groupFormats.computeIfAbsent(group, s -> new TypedChatFormat());
}
return typedChatFormat.getFormat(type, configSupplier);
}
}
public void clear() {
synchronized (this) {
defaultFormat = null;
groupFormats.clear();
}
}
}
private static class TypedChatFormat {
private final Map<ChatType, String> typedFormats;
private String defaultFormat;
TypedChatFormat() {
defaultFormat = null;
typedFormats = new EnumMap<>(ChatType.class);
}
public String getFormat(ChatType type, Supplier<String> configSupplier) {
final String format;
if (type == null) {
if (defaultFormat == null) {
defaultFormat = configSupplier.get();
}
format = defaultFormat;
} else {
format = typedFormats.computeIfAbsent(type, c -> configSupplier.get());
}
return format;
}
}
@Override
public String getWorldAlias(String world) {
return worldAliases.getOrDefault(world.toLowerCase(), world);
@ -1811,9 +1914,7 @@ public class Settings implements net.ess3.api.ISettings {
private List<String> _getDefaultEnabledConfirmCommands() {
final List<String> commands = config.getList("default-enabled-confirm-commands", String.class);
for (int i = 0; i < commands.size(); i++) {
commands.set(i, commands.get(i).toLowerCase());
}
commands.replaceAll(String::toLowerCase);
return commands;
}

View File

@ -31,7 +31,7 @@ public enum ChatType {
*
* <p>This type used when local/global chat features are disabled
*/
UNKNOWN,
UNKNOWN("normal"),
;
private final String key;
@ -40,6 +40,10 @@ public enum ChatType {
this.key = name().toLowerCase(Locale.ENGLISH);
}
ChatType(final String key) {
this.key = key;
}
/**
* @return Lowercase name of the chat type.
*/

View File

@ -914,6 +914,7 @@ chat:
# Chat formatting can be done in two ways, you can either define a standard format for all chat.
# Or you can give a group specific chat format, to give some extra variation.
# For each of these formats, you can specify a sub format for each chat type.
# For more information of chat formatting, check out the wiki: http://wiki.ess3.net/wiki/Chat_Formatting
# Note: Using the {PREFIX} and {SUFFIX} placeholders along with {DISPLAYNAME} may cause double prefixes/suffixes to be shown in chat unless add-prefix-suffix is uncommented and set to false.
@ -936,10 +937,22 @@ chat:
#format: '&7[{GROUP}]&r {DISPLAYNAME}&7:&r {MESSAGE}'
#format: '&7{PREFIX}&r {DISPLAYNAME}&r &7{SUFFIX}&r: {MESSAGE}'
# You can also specify a format for each type of chat.
#format:
# normal: '{WORLDNAME} {DISPLAYNAME}&7:&r {MESSAGE}'
# question: '{WORLDNAME} &4{DISPLAYNAME}&7:&r {MESSAGE}'
# shout: '{WORLDNAME} &c[{GROUP}]&r &4{DISPLAYNAME}&7:&c {MESSAGE}'
# You can specify a format for each group.
group-formats:
# default: '{WORLDNAME} {DISPLAYNAME}&7:&r {MESSAGE}'
# admins: '{WORLDNAME} &c[{GROUP}]&r {DISPLAYNAME}&7:&c {MESSAGE}'
# You can also specify a format for each type of chat for each group.
# admins:
# question: '{WORLDNAME} &4{DISPLAYNAME}&7:&r {MESSAGE}'
# shout: '{WORLDNAME} &c[{GROUP}]&r &4{DISPLAYNAME}&7:&c {MESSAGE}'
# If you are using group formats make sure to remove the '#' to allow the setting to be read.
# Note: Group names are case-sensitive so you must match them up with your permission plugin.

View File

@ -76,7 +76,7 @@ public abstract class AbstractChatHandler {
// This listener should apply the general chat formatting only...then return control back the event handler
event.setMessage(FormatUtil.formatMessage(user, "essentials.chat", event.getMessage()));
if (ChatColor.stripColor(event.getMessage()).length() == 0) {
if (ChatColor.stripColor(event.getMessage()).isEmpty()) {
event.setCancelled(true);
return;
}
@ -91,7 +91,8 @@ public abstract class AbstractChatHandler {
final String suffix = FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(player));
final Team team = player.getScoreboard().getPlayerTeam(player);
String format = ess.getSettings().getChatFormat(group);
final ChatType chatType = chat.getType();
String format = ess.getSettings().getChatFormat(group, chat.getRadius() > 0 && chatType == ChatType.UNKNOWN ? ChatType.LOCAL : chatType);
format = format.replace("{0}", group);
format = format.replace("{1}", ess.getSettings().getWorldAlias(world));
format = format.replace("{2}", world.substring(0, 1).toUpperCase(Locale.ENGLISH));
@ -104,7 +105,7 @@ public abstract class AbstractChatHandler {
format = format.replace("{9}", nickname == null ? username : nickname);
// Local, shout and question chat types are only enabled when there's a valid radius
if (chat.getRadius() > 0 && event.getMessage().length() > 0) {
if (chat.getRadius() > 0 && !event.getMessage().isEmpty()) {
if (event.getMessage().length() > 1 && ((chat.getType() == ChatType.SHOUT && event.getMessage().charAt(0) == ess.getSettings().getChatShout()) || (chat.getType() == ChatType.QUESTION && event.getMessage().charAt(0) == ess.getSettings().getChatQuestion()))) {
event.setMessage(event.getMessage().substring(1));
}
@ -142,7 +143,7 @@ public abstract class AbstractChatHandler {
final User user = chat.getUser();
if (event.getMessage().length() > 0) {
if (!event.getMessage().isEmpty()) {
if (chat.getType() == ChatType.UNKNOWN) {
if (!user.isAuthorized("essentials.chat.local")) {
user.sendTl("notAllowedToLocal");
@ -288,7 +289,7 @@ public abstract class AbstractChatHandler {
}
ChatType getChatType(final User user, final String message) {
if (message.length() == 0) {
if (message.isEmpty()) {
//Ignore empty chat events generated by plugins
return ChatType.UNKNOWN;
}