Skip to content

Commit

Permalink
Merge pull request #61 from 4drian3d/feat/mini-support
Browse files Browse the repository at this point in the history
Added MiniMessage and MiniPlaceholders integration
  • Loading branch information
4drian3d committed Jun 18, 2023
2 parents ca0f6b0 + 78df517 commit adaf24b
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 100 deletions.
3 changes: 2 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ dependencies {
compileOnly(libs.hikaricp)

compileOnly(libs.adventure.api)
compileOnly(libs.adventure.serializer.legacy)
compileOnly(libs.adventure.minimessage)
compileOnly(libs.log4j2)
compileOnly(libs.miniplaceholders)

compileOnly(libs.annotations)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import me.xneox.epicguard.core.user.ConnectingUser;
import me.xneox.epicguard.core.util.TextUtils;
import me.xneox.epicguard.core.util.ToggleState;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;

public abstract sealed class AbstractCheck implements Comparable<AbstractCheck>
Expand All @@ -40,7 +40,7 @@ public abstract sealed class AbstractCheck implements Comparable<AbstractCheck>
protected final EpicGuard epicGuard;

private final int priority;
private final TextComponent detectionMessage;
private final Component detectionMessage;

protected AbstractCheck(@NotNull EpicGuard epicGuard, @NotNull List<String> detectionMessage, int priority) {
this.epicGuard = epicGuard;
Expand Down Expand Up @@ -76,12 +76,12 @@ public boolean evaluate(ToggleState state, boolean expression) {
}

/**
* A formatted {@link TextComponent} which is a disconnect message for this check.
* A formatted {@link Component} which is a disconnect message for this check.
*
* @return disconnect message of this check
*/
@NotNull
public TextComponent detectionMessage() {
public Component detectionMessage() {
return this.detectionMessage;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import me.xneox.epicguard.core.util.TextUtils;
import me.xneox.epicguard.core.util.VersionUtils;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import org.jetbrains.annotations.NotNull;

/**
Expand All @@ -55,15 +57,15 @@ public CommandHandler(EpicGuard epicGuard) {
public void handleCommand(@NotNull String[] args, @NotNull Audience audience) {
// No arguments provided - send the version message.
if (args.length < 1) {
audience.sendMessage(TextUtils.component("&#99ff00 You are running EpicGuard v" + VersionUtils.CURRENT_VERSION +
" on " + this.epicGuard.platform().platformVersion()));
audience.sendMessage(TextUtils.component("&#99ff00 Run &l/guard help &#99ff00to see available commands and statistics"));
audience.sendMessage(Component.text("You are running EpicGuard v" + VersionUtils.CURRENT_VERSION +
" on " + this.epicGuard.platform().platformVersion(), TextColor.color(0x99ff00)));
audience.sendMessage(TextUtils.cachedComponent("<#99ff00> Run <bold><white>/guard help</bold> to see available commands and statistics"));
return;
}

var subCommand = this.commandMap.get(args[0]);
if (subCommand == null) {
audience.sendMessage(TextUtils.component(this.epicGuard.messages().command().prefix() + this.epicGuard.messages().command().unknownCommand()));
audience.sendMessage(TextUtils.cachedComponent(this.epicGuard.messages().command().prefix() + this.epicGuard.messages().command().unknownCommand()));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ public class SaveCommand implements SubCommand {
public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) {
try {
epicGuard.storageManager().database().save();
audience.sendMessage(TextUtils.component(epicGuard.messages().command().prefix() + "&aData has been saved successfully."));
audience.sendMessage(TextUtils.component(epicGuard.messages().command().prefix() + "<red>Data has been saved successfully."));
} catch (SQLException ex) {
audience.sendMessage(TextUtils.component(epicGuard.messages().command().prefix() +
"&cAn exception occurred when saving data. See console for details."));
"<red>An exception occurred when saving data. See console for details."));
LogUtils.catchException("Could not save data to the SQL database (command-induced)", ex);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public class MessagesConfiguration {
private Command command = new Command();
private Disconnect disconnect = new Disconnect();

private String actionbarMonitor = "&cEpicGuard &8// &6%cps% &7connections/s &8| %status%";
private String actionbarNoAttack = "&7No attack...";
private String actionbarAttack = "&cAttack detected!";
private String actionbarMonitor = "<red>EpicGuard <dark_gray>// <gold>%cps% <gray>connections/s <dark_gray>| %status%";
private String actionbarNoAttack = "<gray>No attack...";
private String actionbarAttack = "<red>Attack detected!";
private String updateAvailable = "A new update is available: {NEWVER} (You are still on {OLDVER})";

public Command command() {
Expand Down Expand Up @@ -57,54 +57,54 @@ public String updateAvailable() {

@ConfigSerializable
public static class Command {
private String prefix = " &cEpicGuard &8// &7";
private String usage = "&cCorrect usage: &6{USAGE}";
private String unknownCommand = "&cUnknown command, use &6/epicguard &cfor available commands.";
private String whitelistAdd = "&7The user &a{USER} &7has been added to the whitelist.";
private String whitelistRemove = "The user &6{USER} &7has been removed from the whitelist";
private String blacklistAdd = "&7The user &c{USER} &7has been added to the blacklist.";
private String blacklistRemove = "&7The user &6{USER} &7has been removed from the blacklist.";
private String alreadyWhitelisted = "&cThe user &6{USER} &cis already whitelisted!";
private String alreadyBlacklisted = "&cThe user &6{USER} &cis already blacklisted!";
private String notWhitelisted = "&cThe user &6{USER} &cis not in whitelist!";
private String notBlacklisted = "&cThe user &6{USER} &cis not in the blacklist!";
private String reloaded = "&7Succesfully reloaded config and messages!";
private String toggleStatus = "&7You have toggled your attack status!";
private String invalidArgument = "&cCould not resolve address for this nickname, or provided address is invalid.";
private String prefix = " <red>EpicGuard <dark_gray>// <gray>";
private String usage = "<red>Correct usage: <gold>{USAGE}";
private String unknownCommand = "<red>Unknown command, use <gold>/epicguard <red>for available commands.";
private String whitelistAdd = "<gray>The user <green>{USER}</green> has been added to the whitelist.";
private String whitelistRemove = "The user <gold>{USER} <gray>has been removed from the whitelist";
private String blacklistAdd = "<gray>The user <red>{USER}</red> has been added to the blacklist.";
private String blacklistRemove = "<gray>The user <gold>{USER}</gold> has been removed from the blacklist.";
private String alreadyWhitelisted = "<red>The user <gold>{USER}</gold> is already whitelisted!";
private String alreadyBlacklisted = "<red>The user <gold>{USER}</gold> >is already blacklisted!";
private String notWhitelisted = "<red>The user <gold>{USER}</gold> is not in whitelist!";
private String notBlacklisted = "<red>The user <gold>{USER}</gold> is not in the blacklist!";
private String reloaded = "<gray>Succesfully reloaded config and messages!";
private String toggleStatus = "<gray>You have toggled your attack status!";
private String invalidArgument = "<red>Could not resolve address for this nickname, or provided address is invalid.";

private List<String> mainCommand =
List.of(
"",
" &6EpicGuard Protection System &8- &7Running version &f{VERSION}",
" <gold>EpicGuard Protection System <dark_gray>- <gray>Running version <white>{VERSION}",
"",
" &8▸ &7Under attack: {ATTACK}",
" &8▸ &7Connections: &e{CPS}/s",
" &8▸ &7Blacklist: &e{BLACKLISTED-IPS} &7IPs",
" &8▸ &7Whitelist: &e{WHITELISTED-IPS} &7IPs",
" <dark_gray>▸ <gray>Under attack: {ATTACK}",
" <dark_gray>▸ <gray>Connections: <yellow>{CPS}/s",
" <dark_gray>▸ <gray>Blacklist: <yellow>{BLACKLISTED-IPS}</yellow> IPs",
" <dark_gray>▸ <gray>Whitelist: <yellow>{WHITELISTED-IPS}</yellow> IPs",
"",
" &8/&fguard status &8- &7Toggle attack status on actionbar.",
" &8/&fguard reload &8- &7Reload config and messages.",
" &8/&fguard save &8- &7Save data to the database.",
" &8/&fguard analyze <nick/address> &8- &7Perform detailed analysis on specified user.",
" &8/&fguard whitelist <add/remove> <nick/address> &8- &7Whitelist/unwhitelist an address or nickname.",
" &8/&fguard blacklist <add/remove> <nick/address> &8- &7Blacklist/unblacklist an address or nickname.",
" <dark_gray>/<white>guard status </white>- <gray>Toggle attack status on actionbar.",
" <dark_gray>/<white>guard reload </white>- <gray>Reload config and messages.",
" <dark_gray>/<white>guard save </white>- <gray>Save data to the database.",
" <dark_gray>/<white>guard analyze <nick/address> </white>- <gray>Perform detailed analysis on specified user.",
" <dark_gray>/<white>guard whitelist <add/remove> <nick/address> </white>- <gray>Whitelist/unwhitelist an address or nickname.",
" <dark_gray>/<white>guard blacklist <add/remove> <nick/address> </white>- <gray>Blacklist/unblacklist an address or nickname.",
"");

private List<String> analyzeCommand =
List.of(
"",
" &6EpicGuard Analysis System &8- &7Results for &f{ADDRESS}",
" <gold>EpicGuard Analysis System <dark_gray>- <gray>Results for <white>{ADDRESS}",
"",
" &eGeographic Data:",
" &8▸ &7Country: &f{COUNTRY}",
" &8▸ &7City: &f{CITY}",
" <yellow>Geographic Data:",
" <dark_gray>▸ <gray>Country: <white>{COUNTRY}",
" <dark_gray>▸ <gray>City: <white>{CITY}",
"",
" &eKnown Accounts&6 ({ACCOUNT-AMOUNT}):",
" &8▸ &f{NICKNAMES}",
" <yellow>Known Accounts<gold> ({ACCOUNT-AMOUNT}):",
" <dark_gray>▸ <white>{NICKNAMES}",
"",
" &eOther Data:",
" &8▸ &7Whitelisted: {WHITELISTED}",
" &8▸ &7Blacklisted: {BLACKLISTED}",
" <yellow>Other Data:",
" <dark_gray>▸ <gray>Whitelisted: {WHITELISTED}",
" <dark_gray>▸ <gray>Blacklisted: {BLACKLISTED}",
"");

public String prefix() {
Expand Down Expand Up @@ -175,44 +175,44 @@ public List<String> analyzeCommand() {
@ConfigSerializable
public static class Disconnect {
private List<String> geographical = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYour country/city is not allowed on this server.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>Your country/city is not allowed on this server.");

private List<String> blacklisted = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYou have been blacklisted on this server.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>You have been blacklisted on this server.");

private List<String> attackLockdown = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cServer is under attack, please wait some seconds before joining.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>Server is under attack, please wait some seconds before joining.");

private List<String> proxy = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYou are using VPN or Proxy.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>You are using VPN or Proxy.");

private List<String> reconnect = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cJoin the server again.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>Join the server again.");

private List<String> nickname = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYou nickname is not allowed on this server.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>You nickname is not allowed on this server.");

private List<String> accountLimit = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYou have too many accounts on your IP address.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>You have too many accounts on your IP address.");

private List<String> serverListPing = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYou must add our server to your servers list to verify yourself.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>You must add our server to your servers list to verify yourself.");

private List<String> nameSimilarity = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cYour nickname is too similar to other users connecting to the server.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>Your nickname is too similar to other users connecting to the server.");

private List<String> settingsPacket = List.of(
"&8» &7You have been kicked by &bAntiBot Protection&7:",
"&8» &cBot-like behaviour detected, please join the server again.");
"<dark_gray>» <gray>You have been kicked by <aqua>AntiBot Protection</aqua>:",
"<dark_gray>» <red>Bot-like behaviour detected, please join the server again.");

public List<String> geographical() {
return this.geographical;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,18 @@

package me.xneox.epicguard.core.handler;

import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import me.xneox.epicguard.core.EpicGuard;
import me.xneox.epicguard.core.check.AbstractCheck;
import me.xneox.epicguard.core.check.AccountLimitCheck;
import me.xneox.epicguard.core.check.BlacklistCheck;
import me.xneox.epicguard.core.check.GeographicalCheck;
import me.xneox.epicguard.core.check.LockdownCheck;
import me.xneox.epicguard.core.check.NameSimilarityCheck;
import me.xneox.epicguard.core.check.NicknameCheck;
import me.xneox.epicguard.core.check.ProxyCheck;
import me.xneox.epicguard.core.check.ReconnectCheck;
import me.xneox.epicguard.core.check.ServerListCheck;
import me.xneox.epicguard.core.check.*;
import me.xneox.epicguard.core.manager.AttackManager;
import me.xneox.epicguard.core.user.ConnectingUser;
import me.xneox.epicguard.core.util.LogUtils;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;

import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;

/**
* Handler for PreLogin listeners. It performs every antibot check (except SettingsCheck).
*/
Expand Down Expand Up @@ -68,7 +60,7 @@ public PreLoginHandler(EpicGuard epicGuard) {
* @return Disconnect message, or an empty Optional if undetected.
*/
@NotNull
public Optional<TextComponent> onPreLogin(final @NotNull String address, final @NotNull String nickname) {
public Optional<Component> onPreLogin(final @NotNull String address, final @NotNull String nickname) {
LogUtils.debug(() -> "Handling incoming connection: " + address + "/" + nickname);

final AttackManager attackManager = this.epicGuard.attackManager();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package me.xneox.epicguard.core.placeholder;

import io.github.miniplaceholders.api.Expansion;
import me.xneox.epicguard.core.EpicGuardAPI;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;

import static io.github.miniplaceholders.api.utils.Components.*;

public final class Placeholders {
public static void register() {
EpicGuardAPI API = EpicGuardAPI.INSTANCE;
Expansion.builder("epicguard")
.globalPlaceholder("attack_status", (queue, ctx) -> {
final Component STATUS = API.attackManager().isUnderAttack()
? TRUE_COMPONENT
: FALSE_COMPONENT;
return Tag.selfClosingInserting(STATUS);
})
.globalPlaceholder("connections_per_second", (queue, ctx) -> {
final int connections = API.attackManager().connectionCounter();
return Tag.selfClosingInserting(Component.text(connections));
})
.build()
.register();
}
}
38 changes: 22 additions & 16 deletions core/src/main/java/me/xneox/epicguard/core/util/TextUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,56 @@

package me.xneox.epicguard.core.util;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import me.xneox.epicguard.core.EpicGuardAPI;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

public final class TextUtils {
//TODO: Implement Component Cache in MiniMessage migration
private TextUtils() {}
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder()
.character(LegacyComponentSerializer.AMPERSAND_CHAR)
.hexCharacter(LegacyComponentSerializer.HEX_CHAR)
.hexColors()
.build();
private static final MiniMessage SERIALIZER = MiniMessage.miniMessage();
private static final LoadingCache<String, Component> COMPONENT_CACHE = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(SERIALIZER::deserialize);

/**
* Constructs a {@link TextComponent} from legacy string.
* Supports legacy color-codes by "&amp;" and hex colors by "&amp;#"
* Constructs a {@link Component} from string.
* Supports MiniMessage format
*
* @param message the original string
* @return a component created from the string
*/
@NotNull
public static TextComponent component(@NotNull String message) {
public static Component component(@NotNull String message) {
return SERIALIZER.deserialize(message);
}

@NotNull
public static Component cachedComponent(@NotNull String message) {
return COMPONENT_CACHE.get(message);
}

/**
* Builds a multiline {@link TextComponent} from list of strings.
* Builds a multiline {@link Component} from list of strings.
*/
@NotNull
public static TextComponent multilineComponent(@NotNull List<String> list) {
public static Component multilineComponent(@NotNull List<String> list) {
Objects.requireNonNull(list, "Kick message cannot be null!");

var builder = new StringBuilder();
for (String line : list) {
final var builder = new StringBuilder();
for (final String line : list) {
builder.append(line).append('\n');
}
return component(builder.toString());
return cachedComponent(builder.toString());
}

/**
Expand Down
Loading

0 comments on commit adaf24b

Please sign in to comment.