Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3311f0889a | ||
|
|
c05b7ffef4 | ||
|
|
d8c2139df6 | ||
|
|
5c12776348 | ||
|
|
896c320dd7 | ||
|
|
d8cd699012 | ||
|
|
d550c69583 | ||
|
|
4c239b9b5b | ||
|
|
f82eb34588 | ||
|
|
ea0efd88bb | ||
|
|
1fbadaba9c |
No files matched your search
@@ -1,7 +1,7 @@
|
|||||||
# Minecraft bot stress tester
|
# Minecraft bot stress tester
|
||||||
🤖 A simple open source app written in Java used for stress testing Minecraft servers with bots (fake players).
|
🤖 A simple open source app written in Java used for stress testing Minecraft servers with bots (fake players).
|
||||||
💥 It can be also used to test plugins or minigames.
|
💥 It can be also used to test plugins or minigames.
|
||||||
✔️ The MC version of the bots is 1.19.1 (supports 1.19.2).
|
✔️ The MC version of the bots is 1.20 (supports 1.20.x).
|
||||||
For older MC versions please look in the [releases](https://github.com/crpmax/mc-bots/releases " releases").
|
For older MC versions please look in the [releases](https://github.com/crpmax/mc-bots/releases " releases").
|
||||||
|
|
||||||
## 🆒 Features
|
## 🆒 Features
|
||||||
|
|||||||
+3
-2
@@ -3,7 +3,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group 'me.creepermaxcz.mc-bots'
|
group 'me.creepermaxcz.mc-bots'
|
||||||
version '1.2.6'
|
version '1.2.8'
|
||||||
|
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
@@ -16,11 +16,12 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.github.steveice10:mcprotocollib:1.19.2-1'
|
implementation 'com.github.steveice10:mcprotocollib:1.20-1'
|
||||||
implementation 'commons-cli:commons-cli:1.5.0'
|
implementation 'commons-cli:commons-cli:1.5.0'
|
||||||
implementation 'com.diogonunes:JColor:5.2.0'
|
implementation 'com.diogonunes:JColor:5.2.0'
|
||||||
implementation 'dnsjava:dnsjava:3.4.3'
|
implementation 'dnsjava:dnsjava:3.4.3'
|
||||||
implementation 'org.slf4j:slf4j-nop:1.7.32'
|
implementation 'org.slf4j:slf4j-nop:1.7.32'
|
||||||
|
implementation 'org.jline:jline:3.22.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
|||||||
import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException;
|
import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException;
|
||||||
import com.github.steveice10.mc.protocol.data.game.ClientCommand;
|
import com.github.steveice10.mc.protocol.data.game.ClientCommand;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerCombatKillPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerCombatKillPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
|
||||||
@@ -24,9 +23,7 @@ import com.github.steveice10.packetlib.tcp.TcpClientSession;
|
|||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -126,11 +123,9 @@ public class Bot extends Thread {
|
|||||||
|
|
||||||
// Do not write disconnect reason if disconnected by command
|
// Do not write disconnect reason if disconnected by command
|
||||||
if (!manualDisconnecting) {
|
if (!manualDisconnecting) {
|
||||||
//Log.info(" -> " + event.getReason());
|
// Fix broken reason string by finding the content with regex
|
||||||
|
|
||||||
//fix broken reason string by finding the content with regex
|
|
||||||
Pattern pattern = Pattern.compile("content=\"(.*?)\"");
|
Pattern pattern = Pattern.compile("content=\"(.*?)\"");
|
||||||
Matcher matcher = pattern.matcher(event.getReason());
|
Matcher matcher = pattern.matcher(String.valueOf(event.getReason()));
|
||||||
|
|
||||||
StringBuilder reason = new StringBuilder();
|
StringBuilder reason = new StringBuilder();
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
@@ -169,24 +164,24 @@ public class Bot extends Thread {
|
|||||||
client.send(new ServerboundChatCommandPacket(
|
client.send(new ServerboundChatCommandPacket(
|
||||||
text.substring(1),
|
text.substring(1),
|
||||||
timeStamp,
|
timeStamp,
|
||||||
|
0L,
|
||||||
|
Collections.emptyList(),
|
||||||
0,
|
0,
|
||||||
new ArrayList<>(),
|
new BitSet()
|
||||||
true,
|
|
||||||
new ArrayList<>(),
|
|
||||||
null
|
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
// Send chat message
|
// Send chat message
|
||||||
// From 1.19.1 or 1.19, the ServerboundChatPacket needs timestamp, salt and signed signature to generate packet.
|
// From 1.19.1 or 1.19, the ServerboundChatPacket needs timestamp, salt and signed signature to generate packet.
|
||||||
// tmpSignature will provide an empty byte array that can pretend it as signature.
|
// tmpSignature will provide an empty byte array that can pretend it as signature.
|
||||||
// salt is set 0 since this is offline server and no body will check it.
|
// salt is set 0 since this is offline server and no body will check it.
|
||||||
client.send(new ServerboundChatPacket(text,
|
|
||||||
timeStamp,
|
client.send(new ServerboundChatPacket(
|
||||||
|
text,
|
||||||
|
Instant.now().toEpochMilli(),
|
||||||
|
0L,
|
||||||
|
null,
|
||||||
0,
|
0,
|
||||||
new byte[0],
|
new BitSet()
|
||||||
true,
|
|
||||||
new ArrayList<>(),
|
|
||||||
null
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ import com.github.steveice10.mc.auth.util.HTTP;
|
|||||||
import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo;
|
import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo;
|
||||||
import com.github.steveice10.packetlib.ProxyInfo;
|
import com.github.steveice10.packetlib.ProxyInfo;
|
||||||
import org.apache.commons.cli.*;
|
import org.apache.commons.cli.*;
|
||||||
|
import org.jline.reader.LineReader;
|
||||||
|
import org.jline.reader.LineReaderBuilder;
|
||||||
|
import org.jline.reader.UserInterruptException;
|
||||||
|
import org.jline.terminal.Terminal;
|
||||||
|
import org.jline.terminal.TerminalBuilder;
|
||||||
import org.xbill.DNS.Lookup;
|
import org.xbill.DNS.Lookup;
|
||||||
import org.xbill.DNS.Record;
|
import org.xbill.DNS.Record;
|
||||||
import org.xbill.DNS.SRVRecord;
|
import org.xbill.DNS.SRVRecord;
|
||||||
@@ -390,12 +395,22 @@ public class Main {
|
|||||||
}, 1000L, 500L);
|
}, 1000L, 500L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Terminal terminal = TerminalBuilder.builder().build();
|
||||||
|
LineReader lineReader = LineReaderBuilder.builder()
|
||||||
|
.terminal(terminal)
|
||||||
|
.parser(new org.jline.reader.impl.DefaultParser())
|
||||||
|
.build();
|
||||||
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
prompt = "ALL";
|
prompt = "ALL";
|
||||||
while (scanner.hasNextLine()) {
|
|
||||||
String line = scanner.nextLine();
|
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
String line;
|
||||||
|
try {
|
||||||
|
line = lineReader.readLine();
|
||||||
|
} catch (UserInterruptException e) {
|
||||||
|
System.exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (line.isEmpty()) {
|
if (line.isEmpty()) {
|
||||||
System.out.print(getPrompt() + "> ");
|
System.out.print(getPrompt() + "> ");
|
||||||
continue;
|
continue;
|
||||||
@@ -456,16 +471,12 @@ public class Main {
|
|||||||
|
|
||||||
|
|
||||||
// List command
|
// List command
|
||||||
else if (commandName.equalsIgnoreCase("list") || commandName.equalsIgnoreCase("ls"))
|
else if (commandName.equalsIgnoreCase("list") || commandName.equalsIgnoreCase("ls")) {
|
||||||
{
|
|
||||||
Log.info("There are " + bots.size() + " bots connected:");
|
Log.info("There are " + bots.size() + " bots connected:");
|
||||||
for (Bot bot : bots) {
|
for (Bot bot : bots) {
|
||||||
Log.info(bot.getNickname(), bot.hasMainListener() ? "[MainListener]" : "");
|
Log.info(bot.getNickname(), bot.hasMainListener() ? "[MainListener]" : "");
|
||||||
}
|
}
|
||||||
}
|
} else if (commandName.equalsIgnoreCase("leave") || commandName.equalsIgnoreCase("exit")) {
|
||||||
|
|
||||||
else if (commandName.equalsIgnoreCase("leave") || commandName.equalsIgnoreCase("exit"))
|
|
||||||
{
|
|
||||||
int limit = -1;
|
int limit = -1;
|
||||||
if (split.length >= 2) {
|
if (split.length >= 2) {
|
||||||
try {
|
try {
|
||||||
@@ -496,17 +507,12 @@ public class Main {
|
|||||||
bot.disconnect();
|
bot.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
else {
|
|
||||||
Log.warn("Invalid command");
|
Log.warn("Invalid command");
|
||||||
}
|
}
|
||||||
}
|
} else if (controlledBots.size() > 0) {
|
||||||
|
|
||||||
else if (controlledBots.size() > 0) {
|
|
||||||
controlledBots.forEach(bot -> bot.sendChat(line));
|
controlledBots.forEach(bot -> bot.sendChat(line));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
bots.forEach(bot -> bot.sendChat(line));
|
bots.forEach(bot -> bot.sendChat(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ public class MainListener implements SessionListener {
|
|||||||
// Sometimes the message's body gets null.
|
// Sometimes the message's body gets null.
|
||||||
// For example, some commands like /say makes the message content as null.
|
// For example, some commands like /say makes the message content as null.
|
||||||
// However, the message exists as in getMessagePlain(), thus can retrieve message using the method.
|
// However, the message exists as in getMessagePlain(), thus can retrieve message using the method.
|
||||||
if (message == null) { // When this message was null.
|
if (message == null) {
|
||||||
Log.chat(Utils.getFullText((TextComponent) sender, clientboundPlayerChatPacket.getMessagePlain(), Main.coloredChat));
|
Log.chat(Utils.getFullText((TextComponent) sender, Component.text(clientboundPlayerChatPacket.getContent()), Main.coloredChat));
|
||||||
} else { // When message exists.
|
} else {
|
||||||
Log.chat(Utils.getFullText((TextComponent) sender, (TextComponent) message, Main.coloredChat));
|
Log.chat(Utils.getFullText((TextComponent) sender, (TextComponent) message, Main.coloredChat));
|
||||||
}
|
}
|
||||||
chatPrintedOut = true;
|
chatPrintedOut = true;
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import com.google.gson.JsonParser;
|
|||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.TextComponent;
|
import net.kyori.adventure.text.TextComponent;
|
||||||
import net.kyori.adventure.text.TranslatableComponent;
|
import net.kyori.adventure.text.TranslatableComponent;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.Style;
|
import net.kyori.adventure.text.format.Style;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
import net.kyori.adventure.text.format.TextDecoration;
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.w3c.dom.Text;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@@ -28,6 +27,7 @@ public class Utils {
|
|||||||
public static String getFullText(TextComponent message, boolean colored) {
|
public static String getFullText(TextComponent message, boolean colored) {
|
||||||
if (message.children().size() > 0) {
|
if (message.children().size() > 0) {
|
||||||
StringBuilder text = new StringBuilder();
|
StringBuilder text = new StringBuilder();
|
||||||
|
text.append(parseColor(message, colored));
|
||||||
for (Component child : message.children()) {
|
for (Component child : message.children()) {
|
||||||
if (child instanceof TextComponent) {
|
if (child instanceof TextComponent) {
|
||||||
text.append(getFullText((TextComponent) child, colored));
|
text.append(getFullText((TextComponent) child, colored));
|
||||||
@@ -38,15 +38,7 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
return text.toString();
|
return text.toString();
|
||||||
} else {
|
} else {
|
||||||
String out = message.content();
|
return parseColor(message, colored);
|
||||||
if (colored) {
|
|
||||||
if (message.style().color() != null) {
|
|
||||||
List<Attribute> formats = new ArrayList<>(getFormats(message.style().decorations()));
|
|
||||||
formats.add(getColor((NamedTextColor) message.style().color()));
|
|
||||||
out = colorize(out, formats.toArray(new Attribute[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,36 +47,35 @@ public class Utils {
|
|||||||
* From 1.19.1 the protocol does not include sender's information in the message.
|
* From 1.19.1 the protocol does not include sender's information in the message.
|
||||||
* Thus, we need to merge two TextComponent (sender and message) and generate a text that consists of sent message.
|
* Thus, we need to merge two TextComponent (sender and message) and generate a text that consists of sent message.
|
||||||
* This means using old getFullText will just send the message. Which does NOT contain username who sent this message
|
* This means using old getFullText will just send the message. Which does NOT contain username who sent this message
|
||||||
* @param sender The TextComponent for sender.
|
*
|
||||||
|
* @param sender The TextComponent for sender.
|
||||||
* @param message The TextComponent for message.
|
* @param message The TextComponent for message.
|
||||||
* @param colored Whether if this output was colored or not.
|
* @param colored Whether if this output was colored or not.
|
||||||
* @return Returns String in "Username : Message" format.
|
* @return Returns String in "Username : Message" format.
|
||||||
*/
|
*/
|
||||||
public static String getFullText(@Nullable TextComponent sender, TextComponent message, boolean colored) {
|
public static String getFullText(@Nullable TextComponent sender, TextComponent message, boolean colored) {
|
||||||
if (colored) { // Check if we are using colors.
|
if (colored) {
|
||||||
Style messageStyle = message.style();
|
Style messageStyle = message.style();
|
||||||
StringBuilder outString = new StringBuilder();
|
StringBuilder outString = new StringBuilder();
|
||||||
|
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
Style senderStyle = sender.style();
|
Style senderStyle = sender.style();
|
||||||
if (senderStyle.color() != null) { // Generate sender text with color.
|
if (senderStyle.color() != null) { // Generate sender text with color.
|
||||||
NamedTextColor color = (NamedTextColor) senderStyle.color();
|
outString.append(colorizeText(sender.content(), senderStyle.color()));
|
||||||
outString.append(colorize(sender.content(), getColor(color)));
|
|
||||||
} else {
|
} else {
|
||||||
outString.append(sender.content());
|
outString.append(sender.content());
|
||||||
}
|
}
|
||||||
outString.append(" : "); // Add delimiter as : between sender and message.
|
outString.append(" : "); // Add delimiter as : between sender and message.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageStyle.color() != null) { // Generate message text with color.
|
if (messageStyle.color() != null && sender != null) { // Generate message text with color.
|
||||||
NamedTextColor color = (NamedTextColor) messageStyle.color();
|
outString.append(colorizeText(sender.content(), messageStyle.color()));
|
||||||
outString.append(colorize(message.content(), getColor(color)));
|
|
||||||
} else {
|
} else {
|
||||||
outString.append(message.content());
|
outString.append(message.content());
|
||||||
}
|
}
|
||||||
|
|
||||||
return outString.toString();
|
return outString.toString();
|
||||||
} else { // When color formatting was disabled.
|
} else {
|
||||||
if (sender == null)
|
if (sender == null)
|
||||||
return message.content();
|
return message.content();
|
||||||
else
|
else
|
||||||
@@ -92,83 +83,21 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static String parseColor(TextComponent message, boolean colored) {
|
||||||
* A static function that gets full text from text components.
|
String out = message.content();
|
||||||
* From 1.19.1 the protocol does not include sender's information in the message.
|
if (colored) {
|
||||||
* Sometimes the message as component is null. When this happens, this method will show message as String.
|
if (message.style().color() != null) {
|
||||||
* Since this is just a String being represented, this will not have formatting on String.
|
List<Attribute> formats = new ArrayList<>(getFormats(message.style().decorations()));
|
||||||
* @param sender The TextComponent for sender.
|
TextColor color = message.style().color();
|
||||||
* @param message The TextComponent for message.
|
formats.add(Attribute.TEXT_COLOR(color.red(), color.green(), color.blue()));
|
||||||
* @param colored Whether if this output was colored or not.
|
out = colorize(out, formats.toArray(new Attribute[0]));
|
||||||
* @return Returns String in "Username : Message" format.
|
|
||||||
*/
|
|
||||||
public static String getFullText(@Nullable TextComponent sender, String message, boolean colored) {
|
|
||||||
if (colored) { // Check if we are using colors.
|
|
||||||
StringBuilder outString = new StringBuilder();
|
|
||||||
|
|
||||||
if (sender != null) {
|
|
||||||
Style senderStyle = sender.style();
|
|
||||||
if (senderStyle.color() != null) { // Generate sender text with color.
|
|
||||||
NamedTextColor color = (NamedTextColor) senderStyle.color();
|
|
||||||
outString.append(colorize(sender.content(), getColor(color)));
|
|
||||||
} else {
|
|
||||||
outString.append(sender.content());
|
|
||||||
}
|
|
||||||
outString.append(" : "); // Add delimiter as : between sender and message.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outString.append(message);
|
|
||||||
return outString.toString();
|
|
||||||
} else { // When color formatting was disabled.
|
|
||||||
if (sender == null)
|
|
||||||
return message;
|
|
||||||
else
|
|
||||||
return sender.content() + " : " + message;
|
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Attribute getColor(NamedTextColor color) {
|
private static String colorizeText(String text, TextColor color) {
|
||||||
switch (color.toString()) {
|
return colorize(text, Attribute.TEXT_COLOR(color.red(), color.green(), color.blue()));
|
||||||
case "red":
|
|
||||||
return Attribute.BRIGHT_RED_TEXT();
|
|
||||||
case "dark_red":
|
|
||||||
return Attribute.RED_TEXT();
|
|
||||||
|
|
||||||
case "blue":
|
|
||||||
return Attribute.BRIGHT_BLUE_TEXT();
|
|
||||||
case "dark_blue":
|
|
||||||
return Attribute.BLUE_TEXT();
|
|
||||||
|
|
||||||
case "white":
|
|
||||||
return Attribute.BRIGHT_WHITE_TEXT();
|
|
||||||
case "black":
|
|
||||||
return Attribute.BLACK_TEXT();
|
|
||||||
case "gray":
|
|
||||||
return Attribute.WHITE_TEXT();
|
|
||||||
case "dark_gray":
|
|
||||||
return Attribute.BRIGHT_BLACK_TEXT();
|
|
||||||
|
|
||||||
case "aqua":
|
|
||||||
return Attribute.BRIGHT_CYAN_TEXT();
|
|
||||||
case "dark_aqua":
|
|
||||||
return Attribute.CYAN_TEXT();
|
|
||||||
|
|
||||||
case "yellow":
|
|
||||||
return Attribute.BRIGHT_YELLOW_TEXT();
|
|
||||||
case "gold":
|
|
||||||
return Attribute.YELLOW_TEXT();
|
|
||||||
|
|
||||||
case "green":
|
|
||||||
return Attribute.BRIGHT_GREEN_TEXT();
|
|
||||||
case "dark_green":
|
|
||||||
return Attribute.GREEN_TEXT();
|
|
||||||
|
|
||||||
case "purple":
|
|
||||||
return Attribute.BRIGHT_MAGENTA_TEXT();
|
|
||||||
case "dark_purple":
|
|
||||||
return Attribute.MAGENTA_TEXT();
|
|
||||||
}
|
|
||||||
return Attribute.NONE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Attribute> getFormats(Map<TextDecoration, TextDecoration.State> decorations) {
|
public static List<Attribute> getFormats(Map<TextDecoration, TextDecoration.State> decorations) {
|
||||||
@@ -191,7 +120,6 @@ public class Utils {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String translate(TranslatableComponent message) {
|
public static String translate(TranslatableComponent message) {
|
||||||
if (lang == null) {
|
if (lang == null) {
|
||||||
try {
|
try {
|
||||||
@@ -217,8 +145,7 @@ public class Utils {
|
|||||||
for (Component component : message.args()) {
|
for (Component component : message.args()) {
|
||||||
if (component instanceof TranslatableComponent) {
|
if (component instanceof TranslatableComponent) {
|
||||||
placeholders.add(translate((TranslatableComponent) component));
|
placeholders.add(translate((TranslatableComponent) component));
|
||||||
}
|
} else if (component instanceof TextComponent) {
|
||||||
else if (component instanceof TextComponent) {
|
|
||||||
placeholders.add(getFullText((TextComponent) component, false));
|
placeholders.add(getFullText((TextComponent) component, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,5 +155,4 @@ public class Utils {
|
|||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user