Skip to content

Commit

Permalink
add: Player mentions (#34)
Browse files Browse the repository at this point in the history
* Tweak order of link parsing

* add: Player mentions

Co-authored-by: Patbox <[email protected]>
  • Loading branch information
DrexHD and Patbox authored Dec 4, 2022
1 parent f44b481 commit 387b730
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 50 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
maven { url 'https://maven.nucleoid.xyz' }
maven { url 'https://maven.gegy.dev' }
maven { url "https://api.modrinth.com/maven" }
//mavenLocal()
}

Expand All @@ -49,6 +50,7 @@ dependencies {


modCompileOnly("fr.catcore:server-translations-api:1.4.17+1.19.2")
modCompileOnly("maven.modrinth:vanish:1.1.0")
//modLocalRuntime("fr.catcore:server-translations-api:1.4.17+1.19.2")

//modRuntime "supercoder79:databreaker:0.2.7"
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ loader_version=0.14.10
fabric_version=0.66.1+1.19.3

# Mod Properties

mod_version = 2.1.0-development+1.19.3
maven_group = eu.pb4
archives_base_name = styled-chat
Expand Down
75 changes: 25 additions & 50 deletions src/main/java/eu/pb4/styledchat/StyledChatUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import eu.pb4.styledchat.config.data.VersionedChatStyleData;
import eu.pb4.styledchat.ducks.ExtPlayNetworkHandler;
import eu.pb4.styledchat.ducks.ExtSignedMessage;
import eu.pb4.styledchat.parser.LinkParser;
import eu.pb4.styledchat.parser.MentionParser;
import eu.pb4.styledchat.parser.SpoilerNode;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.command.EntitySelector;
Expand Down Expand Up @@ -75,11 +77,24 @@ public static TextNode parseText(String input) {
}

public static NodeParser createParser(ServerCommandSource source) {
return createParser(PlaceholderContext.of(source));
}

public static NodeParser createParser(PlaceholderContext context) {
var config = ConfigManager.getConfig();
var list = new ArrayList<NodeParser>();
var base = createTextParserV1(source);
var base = createTextParserV1(context.source());

list.add(base);

if (config.configData.formatting.parseLinksInChat) {
list.add(new LinkParser(ConfigManager.getConfig().getLinkStyle(context)));
}

if (config.configData.formatting.parseMentionsInChat) {
list.add(new MentionParser(ConfigManager.getConfig().getMentionStyle(context), context));
}

if (config.configData.formatting.markdown) {
var form = new ArrayList<MarkdownLiteParserV1.MarkdownFormat>();

Expand Down Expand Up @@ -127,7 +142,7 @@ public static NodeParser createParser(ServerCommandSource source) {
}


public static TextParserV1 createTextParserV1(ServerCommandSource source) {
public static TextParserV1 createTextParserV1(ServerCommandSource source) {
var parser = new TextParserV1();
Config config = ConfigManager.getConfig();

Expand Down Expand Up @@ -157,15 +172,15 @@ public static Map<String, TextNode> getEmotes(PlaceholderContext context) {
}

public static Text formatFor(PlaceholderContext context, String input) {
var parser = createParser(context.hasPlayer() ? context.player().getCommandSource() : context.server().getCommandSource());
var parser = createParser(context);
var config = ConfigManager.getConfig();
if (StyledChatMod.USE_FABRIC_API) {
input = StyledChatEvents.PRE_MESSAGE_CONTENT.invoker().onPreMessage(input, context);
}

var emotes = getEmotes(context);

var value = additionalParsing(new ParentNode(parser.parseNodes(new LiteralNode(input))), context);
var value = TextNode.asSingle(parser.parseNodes(new LiteralNode(input)));

if (StyledChatMod.USE_FABRIC_API) {
value = StyledChatEvents.MESSAGE_CONTENT.invoker().onMessage(value, context);
Expand Down Expand Up @@ -287,59 +302,19 @@ public static <T> MessageDecorator getCommandDecorator(String context, ServerCom
});
};
}

@Deprecated
public static TextNode additionalParsing(TextNode node, PlaceholderContext context) {
var config = ConfigManager.getConfig();
if (config.configData.formatting.parseLinksInChat) {

if (ConfigManager.getConfig().configData.formatting.parseLinksInChat) {
node = parseLinks(node, context);
}
return node;
}

@Deprecated
public static TextNode parseLinks(TextNode node, PlaceholderContext context) {
if (node instanceof LiteralNode literalNode) {
var style = ConfigManager.getConfig().getLinkStyle(context);
var input = literalNode.value();
var list = new ArrayList<TextNode>();

Matcher matcher = URL_REGEX.matcher(input);
int currentPos = 0;
int currentEnd = input.length();

while (matcher.find()) {
if (currentEnd <= matcher.start()) {
break;
}

String betweenText = input.substring(currentPos, matcher.start());

if (betweenText.length() != 0) {
list.add(new LiteralNode(betweenText));
}

list.add(new ClickActionNode(Placeholders.parseNodes(style, Placeholders.PREDEFINED_PLACEHOLDER_PATTERN, Map.of("link", Text.literal(matcher.group()))).getChildren(), ClickEvent.Action.OPEN_URL, new LiteralNode(matcher.group())));

currentPos = matcher.end();
}

if (currentPos < currentEnd) {
String restOfText = input.substring(currentPos, currentEnd);
if (restOfText.length() != 0) {
list.add(new LiteralNode(restOfText));
}
}

return list.size() == 1 ? list.get(0) : new ParentNode(list.toArray(new TextNode[0]));
} else if (node instanceof ParentTextNode parentTextNode) {
var list = new ArrayList<TextNode>();

for (var child : parentTextNode.getChildren()) {
list.add(parseLinks(child, context));
}

return parentTextNode.copyWith(list.toArray(new TextNode[0]));
}

return node;
return TextNode.asSingle(LinkParser.parse(node, context));
}

public static boolean isHandledByMod(RegistryKey<MessageType> typeKey) {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/eu/pb4/styledchat/config/ChatStyle.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class ChatStyle {
public final TextNode spoilerStyle;
public final String spoilerSymbol;
public final TextNode linkStyle;
public final TextNode mentionStyle;
public final Map<String, TextNode> emoticons = new HashMap<>();
public final Object2BooleanMap<String> formatting = new Object2BooleanOpenHashMap<>();

Expand Down Expand Up @@ -78,6 +79,7 @@ public ChatStyle(ChatStyleData data, ChatStyle defaultStyle) {
this.spoilerStyle = data.spoilerStyle != null ? StyledChatUtils.parseText(data.spoilerStyle) : defaultStyle.spoilerStyle;
this.spoilerSymbol = data.spoilerSymbol != null ? data.spoilerSymbol : defaultStyle.spoilerSymbol;
this.linkStyle = data.linkStyle != null ? StyledChatUtils.parseText(data.linkStyle) : defaultStyle.linkStyle;
this.mentionStyle = data.mentionStyle != null ? StyledChatUtils.parseText(data.mentionStyle) : defaultStyle.mentionStyle;

for (var emoticon : data.emoticons.entrySet()) {
this.emoticons.put(emoticon.getKey(), StyledChatUtils.parseText(emoticon.getValue()));
Expand Down Expand Up @@ -112,6 +114,7 @@ public ChatStyle(ChatStyleData data) {
this.spoilerStyle = data.spoilerStyle != null ? StyledChatUtils.parseText(data.spoilerStyle) : null;
this.spoilerSymbol = data.spoilerSymbol != null ? data.spoilerSymbol : null;
this.linkStyle = data.linkStyle != null ? StyledChatUtils.parseText(data.linkStyle) : null;
this.mentionStyle = data.mentionStyle != null ? StyledChatUtils.parseText(data.mentionStyle) : null;

for (var emoticon : data.emoticons.entrySet()) {
this.emoticons.put(emoticon.getKey(), StyledChatUtils.parseText(emoticon.getValue()));
Expand Down Expand Up @@ -421,6 +424,11 @@ public TextNode getLink() {
return this.linkStyle;
}

@Nullable
public TextNode getMention() {
return this.mentionStyle;
}

@Nullable
public TextNode getSpoilerStyle() {
return this.spoilerStyle;
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/eu/pb4/styledchat/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,19 @@ public TextNode getLinkStyle(PlaceholderContext ctx) {
return this.defaultStyle.getLink();
}

public TextNode getMentionStyle(PlaceholderContext ctx) {
var context2 = PredicateContext.of(ctx.source());
for (var entry : this.permissionStyle) {
if (entry.require.test(context2).success()) {
var text = entry.getMention();
if (text != null) {
return text;
}
}
}
return this.defaultStyle.getMention();
}

public Text getPetDeath(TameableEntity entity, Text vanillaMessage) {
var context2 = PredicateContext.of(entity);
for (var entry : this.permissionStyle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class ChatStyleData implements Cloneable {

@SerializedName("link_style")
public String linkStyle;
@SerializedName("mention_style")
public String mentionStyle;
@SerializedName("spoiler_style")
public String spoilerStyle;
@SerializedName("spoiler_symbol")
Expand Down Expand Up @@ -130,6 +132,7 @@ public static ChatStyleData createDefault() {
data.messages.petDeathMessage = "${default_message}";

data.linkStyle = "<underline><c:#7878ff>${link}";
data.mentionStyle = "<c:#7878ff>%player:displayname%";
data.spoilerStyle = "<gray>${spoiler}";
data.spoilerSymbol = "▌";

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/eu/pb4/styledchat/config/data/ConfigData.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public static class Formatting {
public boolean legacyChatFormatting = false;
@SerializedName("parse_links")
public boolean parseLinksInChat = true;
@SerializedName("parse_mentions")
public boolean parseMentionsInChat = true;
@SerializedName("markdown")
public boolean markdown = true;
@SerializedName("formatting_from_other_mods")
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/eu/pb4/styledchat/parser/LinkParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package eu.pb4.styledchat.parser;

import eu.pb4.placeholders.api.PlaceholderContext;
import eu.pb4.placeholders.api.Placeholders;
import eu.pb4.placeholders.api.node.LiteralNode;
import eu.pb4.placeholders.api.node.TextNode;
import eu.pb4.placeholders.api.node.parent.ClickActionNode;
import eu.pb4.placeholders.api.node.parent.ParentTextNode;
import eu.pb4.placeholders.api.parsers.NodeParser;
import eu.pb4.styledchat.config.ConfigManager;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.Text;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

import static eu.pb4.styledchat.StyledChatUtils.URL_REGEX;

public record LinkParser(TextNode style) implements NodeParser {

@Override
public TextNode[] parseNodes(TextNode node) {
if (node instanceof LiteralNode literalNode) {
var input = literalNode.value();
var list = new ArrayList<TextNode>();

Matcher matcher = URL_REGEX.matcher(input);
int currentPos = 0;
int currentEnd = input.length();

while (matcher.find()) {
if (currentEnd <= matcher.start()) {
break;
}

String betweenText = input.substring(currentPos, matcher.start());

if (betweenText.length() != 0) {
list.add(new LiteralNode(betweenText));
}

list.add(new ClickActionNode(Placeholders.parseNodes(style, Placeholders.PREDEFINED_PLACEHOLDER_PATTERN, Map.of("link", Text.literal(matcher.group()))).getChildren(), ClickEvent.Action.OPEN_URL, new LiteralNode(matcher.group())));

currentPos = matcher.end();
}

if (currentPos < currentEnd) {
String restOfText = input.substring(currentPos, currentEnd);
if (restOfText.length() != 0) {
list.add(new LiteralNode(restOfText));
}
}

return list.toArray(new TextNode[0]);
} else if (node instanceof ParentTextNode parentTextNode) {
var list = new ArrayList<TextNode>();

for (var child : parentTextNode.getChildren()) {
list.addAll(List.of(this.parseNodes(child)));
}

return new TextNode[] { parentTextNode.copyWith(list.toArray(new TextNode[0])) };
}

return new TextNode[] { node };
}

public static TextNode[] parse(TextNode node, PlaceholderContext context) {
return new LinkParser(ConfigManager.getConfig().getLinkStyle(context)).parseNodes(node);
}
}
53 changes: 53 additions & 0 deletions src/main/java/eu/pb4/styledchat/parser/MentionParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package eu.pb4.styledchat.parser;

import eu.pb4.placeholders.api.PlaceholderContext;
import eu.pb4.placeholders.api.Placeholders;
import eu.pb4.placeholders.api.node.LiteralNode;
import eu.pb4.placeholders.api.node.TextNode;
import eu.pb4.placeholders.api.node.parent.ParentTextNode;
import eu.pb4.placeholders.api.parsers.NodeParser;
import me.drex.vanish.api.VanishAPI;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.server.network.ServerPlayerEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public record MentionParser(TextNode style, PlaceholderContext context) implements NodeParser {

public static final boolean VANISH = FabricLoader.getInstance().isModLoaded("melius-vanish");

@Override
public TextNode[] parseNodes(TextNode node) {
if (node instanceof LiteralNode literalNode) {
return parseInput(literalNode.value());
} else if (node instanceof ParentTextNode parentTextNode) {
var list = new ArrayList<TextNode>();

for (var child : parentTextNode.getChildren()) {
list.addAll(List.of(this.parseNodes(child)));
}

return new TextNode[]{parentTextNode.copyWith(list.toArray(new TextNode[]{}))};
}

return new TextNode[]{node};
}

public TextNode[] parseInput(String input) {
if (input.isEmpty()) return new TextNode[]{};
for (ServerPlayerEntity player : context.server().getPlayerManager().getPlayerList()) {
if (VANISH && VanishAPI.isVanished(player)) continue;
int startPos = input.indexOf(player.getEntityName());
if (startPos != -1) {
int endPos = startPos + player.getEntityName().length();
TextNode[] before = parseInput(input.substring(0, startPos));
TextNode mention = TextNode.convert(Placeholders.parseText(style, PlaceholderContext.of(player)));
TextNode[] after = parseInput(input.substring(Math.min(endPos, input.length())));
return Stream.of(before, new TextNode[]{mention}, after).flatMap(Stream::of).toArray(TextNode[]::new);
}
}
return new TextNode[]{new LiteralNode(input)};
}
}

0 comments on commit 387b730

Please sign in to comment.