Fixed some typos in the GUI, added logging for false positive editing, fixed auto-similarity based blocking, and fixed logging related to such.

This commit is contained in:
thetrouper
2024-12-01 14:55:11 -06:00
parent c1be1e4c6a
commit 33a215be22
359 changed files with 436127 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
package me.trouper.sentinel;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import io.github.itzispyder.pdk.PDK;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.data.WhitelistStorage;
import me.trouper.sentinel.data.config.*;
import me.trouper.sentinel.data.config.lang.LanguageFile;
import me.trouper.sentinel.startup.Auth;
import me.trouper.sentinel.startup.Load;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.logging.Logger;
public final class Sentinel extends JavaPlugin {
private static final File dataFolder = new File("plugins/SentinelAntiNuke");
public static final Logger log = Bukkit.getLogger();
private static Sentinel instance;
private static final File violationcfg = new File(Sentinel .dataFolder(),"/violation-config.json");
private static final File cfgfile = new File(Sentinel.dataFolder(),"/main-config.json");
private static final File nbtcfg = new File(Sentinel.dataFolder(), "/nbt-config.json");
private static final File strctcfg = new File(Sentinel.dataFolder(), "/strict.json");
private static final File swrcfg = new File(Sentinel.dataFolder(), "/swears.json");
private static final File fpcfg = new File(Sentinel.dataFolder(), "/false-positives.json");
private static final File advcfg = new File(Sentinel.dataFolder(), "/advanced-config.json");
private static final File cmdWhitelist = new File(Sentinel.dataFolder(), "/storage/whitelist.json");
public static ViolationConfig violationConfig = JsonSerializable.load(violationcfg, ViolationConfig.class, new ViolationConfig());
public static WhitelistStorage whitelist = JsonSerializable.load(cmdWhitelist, WhitelistStorage.class, new WhitelistStorage());
public static MainConfig mainConfig = JsonSerializable.load(cfgfile, MainConfig.class, new MainConfig());
public static FPConfig fpConfig = JsonSerializable.load(fpcfg, FPConfig.class, new FPConfig());
public static SwearsConfig swearConfig = JsonSerializable.load(swrcfg, SwearsConfig.class, new SwearsConfig());
public static StrictConfig strictConfig = JsonSerializable.load(strctcfg, StrictConfig.class, new StrictConfig());
public static NBTConfig nbtConfig = JsonSerializable.load(nbtcfg, NBTConfig.class, new NBTConfig());
public static AdvancedConfig advConfig = JsonSerializable.load(advcfg, AdvancedConfig.class, new AdvancedConfig());
public static LanguageFile lang;
public static File us;
public static ProtocolManager protocolManager;
public static boolean doNoPlugins = false;
@Override
public void onEnable() {
log.info("\n]======------ Pre-load started! ------======[");
PDK.init(this);
instance = this;
us = getFile();
log.info("Loading Config...");
loadConfig();
log.info("Loading ProtocolLib");
if (Bukkit.getServer().getPluginManager().isPluginEnabled("ProtocolLib") && mainConfig.plugin.pluginHider) {
doNoPlugins = true;
protocolManager = ProtocolLibrary.getProtocolManager();
} else {
doNoPlugins = false;
log.warning("Sentinel: ProtocolLib not found. Sentinel will attempt to hide your plugins through Bukkit's systems, although it may not catch everything.");
}
log.info("Language Status: (%s)".formatted(lang.brokenLang));
log.info("Initializing Server ID...");
String serverID = Auth.getServerID();
String license = Sentinel.mainConfig.plugin.license;
String nonce = Auth.getNonce();
int port = Auth.getPort();
log.info("Pre-load finished!\n]====---- Requesting Authentication ----====[ \n- License Key: %s\n- Server ID: %s\n- Nonce: %s\n".formatted(license,serverID,nonce));
Load.load(license,serverID);
}
public static void loadConfig() {
// Init
mainConfig = JsonSerializable.load(cfgfile,MainConfig.class,new MainConfig());
advConfig = JsonSerializable.load(advcfg,AdvancedConfig.class,new AdvancedConfig());
fpConfig = JsonSerializable.load(fpcfg,FPConfig.class,new FPConfig());
strictConfig = JsonSerializable.load(strctcfg,StrictConfig.class,new StrictConfig());
swearConfig = JsonSerializable.load(swrcfg,SwearsConfig.class,new SwearsConfig());
nbtConfig = JsonSerializable.load(nbtcfg,NBTConfig.class,new NBTConfig());
violationConfig = JsonSerializable.load(violationcfg,ViolationConfig.class,new ViolationConfig());
// Save
mainConfig.save();
advConfig.save();
fpConfig.save();
strictConfig.save();
swearConfig.save();
nbtConfig.save();
violationConfig.save();
whitelist = JsonSerializable.load(cmdWhitelist, WhitelistStorage.class, new WhitelistStorage());
whitelist.save();
log.info("Loading Dictionary (%s)...".formatted(Sentinel.mainConfig.plugin.lang));
lang = JsonSerializable.load(LanguageFile.PATH,LanguageFile.class,new LanguageFile());
lang.save();
}
@Override
public void onDisable() {
// Plugin shutdown logic
log.info("Sentinel has disabled! (%s) Your server is now no longer protected!".formatted(getDescription().getVersion()));
}
public static Sentinel getInstance() {
return instance;
}
public static File dataFolder() {
return dataFolder;
}
}

View File

@@ -0,0 +1,33 @@
package me.trouper.sentinel.data;
public class Emojis {
public static String space = "<:space:1210008300515762238>";
public static String rightSort = "<:rightSort:1210008337144479754>";
public static String rightArrow = "<:rightArrow:1210008295738179594>";
public static String rightDoubleArrow = "<:rightDoubleArrow:1210008296723976224>";
public static String activity = "<:activity:1125785527468167178>";
public static String alarm = "<:alarm:1210008289635475547>";
public static String target = "<:target:1210008303992701068>";
public static String bot = "<:bot:1125791121851826206>";
public static String cancel = "<:cancel:1125785769471127694>";
public static String creation = "<:creation:1125790610729730109>";
public static String date = "<:date:1125790434443145297>";
public static String kick = "<:kick:1125785612595761212>";
public static String members = "<:members:1125791101199077426>";
public static String mute = "<:mute:1125789032937435247>";
public static String noDM = "<:noDM:1210008293729370204>";
public static String owner = "<:owner:1125791175559876669>";
public static String potentialDanger = "<:potentialDanger:1125788513971998741>";
public static String roles = "<:roles:1125790513933594645>";
public static String separator = "<:separator:1125790817626357861>";
public static String splash = "<:splash:1125791213933563905>";
public static String success = "<:success:1210008354039275570>";
public static String suspicious = "<:suspicious:1125790709371371682>";
public static String trustedAdmin = "<:trustedAdmin:1210008362230743080>";
public static String upvoter = "<:upvoter:1125790659735977994>";
public static String vanity = "<:vanity:1125791060594004039>";
public static String webhook = "<:webhook:1125790545638330388>";
public static String failure = "<:failure:1210008290625462432>";
public static String nuke = "<:nuke:1210008294756712478>";
public static String member = "<:member:1210008291174785105>";
}

View File

@@ -0,0 +1,20 @@
package me.trouper.sentinel.data;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.types.WhitelistedBlock;
import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;
public class WhitelistStorage implements JsonSerializable<WhitelistStorage> {
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/storage/whitelist.json");
file.getParentFile().mkdirs();
return file;
}
public ConcurrentLinkedQueue<WhitelistedBlock> whitelistedCMDBlocks = new ConcurrentLinkedQueue<>();
}

View File

@@ -0,0 +1,83 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AdvancedConfig implements JsonSerializable<AdvancedConfig> {
public static String nonce = "%%__NONCE__%%";
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/advanced-config.json");
file.getParentFile().mkdirs();
return file;
}
public List<String> fakePlugins = Arrays.asList(
"nocheatplus",
"negativity",
"warden",
"horizon",
"illegalstack",
"coreprotect",
"exploitsx",
"vulcan",
"abc",
"spartan",
"kauri",
"anticheatreloaded",
"witherac",
"godseye",
"matrix",
"wraith",
"antixrayheuristics",
"grimac"
);
public List<String> versionAliases = List.of(
"version",
"bukkit:version",
"ver",
"bukkit:ver",
"about",
"bukkit:about",
"?",
"bukkit:?",
"pl",
"bukkit:pl",
"plugins",
"bukkit:plugins",
"help",
"bukkit:help"
);
public Map<String, String> leetPatterns = new HashMap<>() {{
put("0", "o");
put("1", "i");
put("3", "e");
put("4", "a");
put("5", "s");
put("6", "g");
put("7", "l");
put("8","ate");
put("$", "s");
put("!", "i");
put("|_|","u");
put("|", "i");
put("+", "t");
put("#", "h");
put("@", "a");
put("<", "c");
put("v", "u");
}};
public String allowedCharRegex = "[A-Za-z0-9\\[,./?><|\\]§()*&^%$#@!~`{}:;'\"-_]";
public String falsePosRegex = "";
public String swearRegex = "";
public String strictRegex = "";
public String urlRegex = "\\b(?:(?:https?|ftp):\\/\\/)?(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:com|org|net|int|edu|gov|mil|arpa|biz|info|mobi|app|name|aero|jobs|museum|travel|a[c-gil-oq-uwxz]|b[abd-jmnoq-tvwyz]|c[acdf-ik-orsu-z]|d[dejkmoz]|e[ceghr-u]|f[ijkmor]|g[abd-ilmnp-uwy]|h[kmnrtu]|i[delmnoq-t]|j[emop]|k[eghimnprwyz]|l[abcikr-vy]|m[acdeghk-z]|n[acefgilopruz]|om|p[ae-hk-nrstwy]|qa|r[eosuw]|s[a-eg-or-vxyz]|t[cdfghj-prtvwz]|u[agksyz]|v[aceginu]|w[fs]|y[etu]|z[amrw])))(?::\\d{2,5})?(?:\\/\\S*)?\\b";
}

View File

@@ -0,0 +1,79 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FPConfig implements JsonSerializable<FPConfig> {
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/false-positives.json");
file.getParentFile().mkdirs();
return file;
}
public List<String> swearWhitelist = new ArrayList<>(Arrays.asList(
"but then",
"was scamming",
"an alt",
"can also",
"analysis",
"analytics",
"arsenal",
"assassin",
"as saying",
"assert",
"assign",
"assimil",
"assist",
"associat",
"assum",
"assur",
"basement",
"bass",
"cass",
"butter",
"canvass",
"cocktail",
"cumber",
"document",
"evaluate",
"exclusive",
"expensive",
"explain",
"expression",
"grape",
"grass",
"harass",
"hotwater",
"identit",
"kassa",
"kassi",
"lass",
"leafage",
"libshitz",
"magnacumlaude",
"mass",
"mocha",
"pass",
"phoebe",
"phoenix",
"push it",
"sassy",
"saturday",
"scrap",
"serfage",
"sexist",
"shoe",
"stitch",
"therapist",
"but its",
"whoever",
" again"
));
}

View File

@@ -0,0 +1,82 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
import java.util.List;
public class MainConfig implements JsonSerializable<MainConfig> {
public static String user = "%%__USER__%%";
public static String username = "%%__USERNAME__%%";
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/main-config.json");
file.getParentFile().mkdirs();
return file;
}
public Plugin plugin = new Plugin();
public Chat chat = new Chat();
public boolean debugMode = false;
public class Plugin {
public String license = "null";
public String prefix = "§d§lSentinel §8» §7";
public String webhook = "https://discord.com/api/webhooks/id/token";
public String lang = "en-us.json";
public List<String> trustedPlayers = List.of(
"049460f7-21cb-42f5-8059-d42752bf406f"
);
public boolean reopCommand = false;
public boolean pluginHider = true;
public String identifier = "My Server (Edit in main-config.json)";
}
public class Chat {
public AntiSwear swearFilter = new AntiSwear();
public AntiSpam spamFilter = new AntiSpam();
public boolean useAntiURL = true;
public boolean useSwearRegex = false;
public boolean useStrictRegex = false;
public boolean useAntiUnicode = true;
public class AntiSpam {
public boolean enabled = true;
public int defaultGain = 1;
public int lowGain = 2;
public int mediumGain = 4;
public int highGain = 6;
public int heatDecay = 1;
public int blockSimilarity = 99;
public int blockHeat = 10;
public int punishHeat = 25;
public List<String> punishCommands = List.of(
"clearchat",
"mute %player% 1m Please refrain from spamming!"
);
}
public class AntiSwear {
public boolean enabled = true;
public int lowScore = 0;
public int mediumLowScore = 1;
public int mediumScore = 3;
public int mediumHighScore = 5;
public int highScore = 7;
public int regexScore = 4;
public int scoreDecay = 3;
public int punishScore = 20;
public List<String> swearPunishCommands = List.of(
"mute %player% 15m Do not attempt to bypass the Profanity Filter"
);
public List<String> strictPunishCommands = List.of(
"mute %player% 1h Discriminatory speech is not tolerated on this server!"
);
}
}
}

View File

@@ -0,0 +1,60 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
public class NBTConfig implements JsonSerializable<NBTConfig> {
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/nbt-config.json");
file.getParentFile().mkdirs();
return file;
}
public boolean allowName = true;
public boolean allowLore = true;
public boolean allowAttributes = false;
public boolean allowPotions = false;
public int globalMaxEnchant = 5;
public int maxMending = 1;
public int maxUnbreaking = 3;
public int maxVanishing = 1;
public int maxAquaAffinity = 1;
public int maxBlastProtection = 4;
public int maxCurseOfBinding = 1;
public int maxDepthStrider = 3;
public int maxFeatherFalling = 4;
public int maxFireProtection = 4;
public int maxFrostWalker = 2;
public int maxProjectileProtection = 4;
public int maxProtection = 4;
public int maxRespiration = 3;
public int maxSoulSpeed = 3;
public int maxThorns = 3;
public int maxSwiftSneak = 3;
public int maxBaneOfArthropods = 5;
public int maxEfficiency = 5;
public int maxFireAspect = 2;
public int maxLooting = 3;
public int maxImpaling = 5;
public int maxKnockback = 2;
public int maxSharpness = 5;
public int maxSmite = 5;
public int maxSweepingEdge = 3;
public int maxChanneling = 1;
public int maxFlame = 1;
public int maxInfinity = 1;
public int maxLoyalty = 3;
public int maxRiptide = 3;
public int maxMultishot = 1;
public int maxPiercing = 4;
public int maxPower = 5;
public int maxPunch = 2;
public int maxQuickCharge = 3;
public int maxFortune = 3;
public int maxLuckOfTheSea = 3;
public int maxLure = 3;
public int maxSilkTouch = 1;
}

View File

@@ -0,0 +1,28 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class StrictConfig implements JsonSerializable<StrictConfig> {
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/strict.json");
file.getParentFile().mkdirs();
return file;
}
public List<String> strict = new ArrayList<>() {{
add("nigg");
add("niger");
add("nlgg");
add("nlger");
add("njgg");
add("tranny");
add("fag");
add("beaner");
}};
}

View File

@@ -0,0 +1,97 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
import java.util.List;
public class SwearsConfig implements JsonSerializable<SwearsConfig> {
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/swears.json");
file.getParentFile().mkdirs();
return file;
}
public List<String> swears = List.of(
"anal",
"anus",
"arse",
"ass",
"ballsack",
"balls",
"bastard",
"bitch",
"btch",
"biatch",
"blowjob",
"bollock",
"bollok",
"boner",
"boob",
"bugger",
"butt",
"choad",
"clitoris",
"cock",
"coon",
"crap",
"cum",
"cunt",
"dick",
"dildo",
"douchebag",
"dyke",
"feck",
"fellate",
"fellatio",
"felching",
"fuck",
"fudgepacker",
"flange",
"gtfo",
"hoe",
"horny",
"incest",
"jerk",
"jizz",
"labia",
"masturb",
"muff",
"nazi",
"nipple",
"nips",
"nude",
"pedophile",
"penis",
"piss",
"poop",
"porn",
"prick",
"prostit",
"pube",
"pussie",
"pussy",
"queer",
"rape",
"rapist",
"retard",
"rimjob",
"scrotum",
"sex",
"shit",
"slut",
"spunk",
"stfu",
"suckmy",
"tits",
"tittie",
"titty",
"turd",
"twat",
"vagina",
"wank",
"whore"
);
}

View File

@@ -0,0 +1,151 @@
package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.startup.Load;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ViolationConfig implements JsonSerializable<SwearsConfig> {
@Override
public File getFile() {
File file = new File(Sentinel.dataFolder(), "/violation-config.json");
file.getParentFile().mkdirs();
return file;
}
public CommandBlockEdit commandBlockEdit = new CommandBlockEdit();
public CommandBlockExecute commandBlockExecute = new CommandBlockExecute();
public CommandBlockMinecartPlace commandBlockMinecartPlace = new CommandBlockMinecartPlace();
public CommandBlockMinecartUse commandBlockMinecartUse = new CommandBlockMinecartUse();
public CommandBlockPlace commandBlockPlace = new CommandBlockPlace();
public CommandBlockUse commandBlockUse = new CommandBlockUse();
public CommandExecute commandExecute = new CommandExecute();
public CreativeHotbarAction creativeHotbarAction = new CreativeHotbarAction();
public class CommandBlockEdit {
public boolean enabled = true;
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class CommandBlockMinecartPlace {
public boolean enabled = true;
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class CommandBlockMinecartUse {
public boolean enabled = true;
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class CommandBlockPlace {
public boolean enabled = true;
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class CommandBlockUse {
public boolean enabled = true;
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class CreativeHotbarAction {
public boolean enabled = true;
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class CommandExecute {
public Dangerous dangerous = new Dangerous();
public Logged logged = new Logged();
public Specific specific = new Specific();
public class Dangerous {
public boolean enabled = true;
public List<String> commands = List.of(
"op",
"deop",
"stop",
"restart",
"execute",
"sudo",
"esudo",
"fill",
"setblock",
"data",
"whitelist",
"lp",
"luckperms",
"perms",
"perm",
"permission",
"permissions",
"pm",
"pluginmanager",
"rl",
"reload",
"plugman"
);
public boolean deop = true;
public boolean logToDiscord = true;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
public class Logged {
public boolean enabled = true;
public List<String> commands = List.of(
"give",
"item"
);
public boolean logToDiscord = true;
}
public class Specific {
public boolean enabled = true;
public boolean logToDiscord = false;
public boolean punish = false;
public List<String> punishmentCommands = List.of(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
}
}
public class CommandBlockExecute {
public boolean enabled = true;
public boolean destroyBlock = false;
public boolean attemptRestore = true;
public boolean logToDiscord = false;
}
}

View File

@@ -0,0 +1,265 @@
package me.trouper.sentinel.data.config.lang;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
public class LanguageFile implements JsonSerializable<LanguageFile> {
public static final File PATH = new File(Sentinel.dataFolder(), "/lang/" + Sentinel.mainConfig.plugin.lang);
public LanguageFile() {}
@Override
public File getFile() {
return PATH;
}
public String brokenLang = "Sentinel language is working!";
public Permissions permissions = new Permissions();
public class Permissions {
public String noPermission = "§cInsufficient Permissions!";
public String elevatingPerms = "Elevating your permissions...";
public String logElevatingPerms = "Elevating the permissions of %s";
public String alreadyOp = "You are already a server operator!";
public String logAlreadyOp = "The permissions of %s are already elevated! Retrying...";
public String noTrust = "You are not a trusted user!";
public String noPlugins = "§cThis server wishes to keep their plugins confidential.";
}
public Cooldown cooldown = new Cooldown();
public class Cooldown {
public String onCooldown = "This action is on cooldown!";
}
public Reports reports = new Reports();
public class Reports {
public String falsePositiveSuccess = "Successfully reported a false positive!";
public String reportingFalsePositive = "Sending report to staff...";
public String noReport = "§cThe report you requested either does not exist, or has expired!";
}
public PlayerInteraction playerInteraction = new PlayerInteraction();
public class PlayerInteraction {
public String noOnlinePlayer = "§cYou must provide an online player to send a message to!";
public String noMessageProvided = "§cYou must provide a message to send!";
public String noReply = "§cYou have nobody to reply to!";
public String messageSent = "§d§lMessage §8» §b[§fYou §e>§f %1$s§b] §7%2$s";
public String messageReceived = "§d§lMessage §8» §b[§f%1$s §e>§f You§b] §7%2$s";
}
public SocialSpy socialSpy = new SocialSpy();
public class SocialSpy {
public String enabled = "SocialSpy is now enabled.";
public String disabled = "SocialSpy is now disabled.";
public String spyMessage = "§d§lSpy §8» §b§n%1$s§7 has messaged §b§n%2$s§7.";
public String spyMessageHover = "§8]==-- §d§lSocialSpy §8--==[\n§bSender: §f%1$S\n§bReceiver: §f%2$S\n§bMessage: §f%3$S";
}
public AutomatedActions automatedActions = new AutomatedActions();
public class AutomatedActions {
public String actionAutomaticReportable = "§7This action was preformed automatically \n§7by the §bSentinel Chat Filter§7 algorithm!\n§8§o(Click to report false positive)";
}
public Violations violations = new Violations();
public class Violations {
public Chat chat = new Chat();
public class Chat {
public Profanity profanity = new Profanity();
public class Profanity {
public String prevent = "has been prevented from swearing.";
public String autoPunish = "has been auto-punished for swearing.";
public String preventWarning = "Do not use profanity in chat. Any attempt to bypass this filter will be detected, and you will be punished.";
public String autoPunishWarning = "&cYou have been auto-punished for attempting to bypass the profanity filter!";
public String treeTitle = "The Profanity Filter has been triggered.";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String score = "Score";
public String reportInfoTitle = "Anti-Swear Detection";
public String originalMessage = "Original Message";
public String processedMessage = "Processed Message";
public String severity = "Severity";
public String actionTitle = "Actions";
public String blockAction = "Blocked the message";
public String commandAction = "Executed Punishment Commands";
}
public Regex regex = new Regex();
public class Regex {
public String autoPunish = "has been auto-punished for slurs. (Regex)";
public String regexTrigger = "has triggered a regex blocker.";
public String urlBlockName = "URL Regex Blocker";
public String urlBlockMessage = "Your message has been withheld. Do not link to websites.";
public String unicodeBlockName = "Unicode Regex Blocker";
public String unicodeBlockMessage = "Your message has been withheld. Please only use characters found on your keyboard.";
public String swearBlockName = "Swear Regex Blocker";
public String swearBlockMessage = "Your message has been withheld for containing blocked words.";
public String strictBlockName = "Strict Regex Blocker";
public String strictBlockMessage = "Your message has been withheld for containing slurs.";
public String treeTitle = "A Regex Filter has been triggered.";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String score = "Score";
public String reportInfoTitle = "%s Detection";
public String originalMessage = "Original Message";
public String flaggedMessage = "Flagged Message";
public String actionTitle = "Actions";
public String blockAction = "Blocked the message";
public String commandAction = "Executed Punishment Commands";
}
public Spam spam = new Spam();
public class Spam {
public String autoPunish = "has been auto-punished for spamming.";
public String spamWarning = "might be spamming!";
public String preventWarning = "Do not spam in chat! Please wait before sending another message.";
public String autoPunishWarning = "&cYou have been auto-punished for violating the anti-spam repetitively!";
public String treeTitle = "The Anti-Spam has been triggered.";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String heat = "Heat";
public String reportInfoTitle = "Anti-Spam Detection";
public String previousMessage = "Previous Message";
public String currentMessage = "Current Message";
public String similarity = "Similarity";
public String actionTitle = "Actions";
public String blockAction = "Blocked the message";
public String commandAction = "Executed Punishment Commands";
}
}
public CommandBlockEdit commandBlockEdit = new CommandBlockEdit();
public class CommandBlockEdit {
public String playerAttemptEdit = "A player has attempted to edit a command block!";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String violationInfoTitle = "Command Block Edit Info";
public String blockLocation = "Block Location";
public String insertedCommand = "Inserted Command";
}
public CommandBlockExecute commandBlockExecute = new CommandBlockExecute();
public class CommandBlockExecute {
public String commandBlockWhitelistTripped = "Command block whitelist has been tripped.";
public String actionsTitle = "Actions";
public String commandBlockInfoTitle = "Command Block Info";
public String blockLocation = "Block Location";
public String executedCommand = "Executed Command";
public String destroyedBlock = "Destroyed block";
public String preventExecution = "Prevented Execution";
public String restore = "Restore";
public String restoreSuccess = "Success";
public String restoreFailure = "Failure";
public String loggedToDiscord = "Logged to Discord";
}
public CommandBlockMinecartPlace commandBlockMinecartPlace = new CommandBlockMinecartPlace();
public class CommandBlockMinecartPlace {
public String detectionChat = "&b&n%s&r &7has attempted to place a command block minecart.";
public String detectionTree = "A player has attempted to place a command block minecart!";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String blockLocation = "Block Location";
public String minecartPlaceInfoTitle = "Minecart Place Info";
public String locationFormat = "X: %s Y: %s Z: %s";
public String blockLocationFormat = "World: %s X: %s Y: %s Z: %s";
}
public CommandBlockMinecartUse commandBlockMinecartUse = new CommandBlockMinecartUse();
public class CommandBlockMinecartUse {
public String detectionChat = "&b&n%s&r &7has attempted to use a command block minecart.";
public String detectionTree = "A player has attempted to use a command block minecart!";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String cartLocation = "Cart Location";
public String minecartUseInfoTitle = "Minecart Use Info";
public String locationFormat = "X: %s Y: %s Z: %s";
public String cartLocationFormat = "World: %s X: %s Y: %s Z: %s";
}
public CommandBlockPlace commandBlockPlace = new CommandBlockPlace();
public class CommandBlockPlace {
public String detectionChat = "&b&n%s&r &7has attempted to place a command block.";
public String detectionTree = "A player has attempted to place a command block!";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String blockLocation = "Block Location";
public String commandBlockEditInfoTitle = "Command Block Edit Info";
public String locationFormat = "X: %s Y: %s Z: %s";
public String blockLocationFormat = "World: %s X: %s Y: %s Z: %s";
public String insertedCommand = "Inserted Command";
public String insertedCommandUploadedTo = "Inserted Command Uploaded to";
}
public CommandBlockUse commandBlockUse = new CommandBlockUse();
public class CommandBlockUse {
public String detectionChat = "&b&n%s&r &7has attempted to use a command block.";
public String detectionTree = "A player has attempted to use a command block!";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String blockLocation = "Block Location";
public String commandBlockUseInfoTitle = "Command Block Use Info";
public String locationFormat = "X: %s Y: %s Z: %s";
public String blockLocationFormat = "World: %s X: %s Y: %s Z: %s";
public String commandInside = "Command Inside";
public String commandUploadedTo = "Command Uploaded to";
}
public CommandExecute commandExecute = new CommandExecute();
public class CommandExecute {
public String specificCommandDetection = "A player has attempted to run a specific command.";
public String dangerousCommandDetection = "A player has attempted to run a dangerous command.";
public String loggedCommandDetection = "A player has ran a logged command.";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String commandField = "Command";
public String commandUploadedTo = "Command Uploaded to";
public String violationInfoTitle = "Violation Info";
public String locationFormat = "X: %s Y: %s Z: %s";
public String specificCommandViolation = "&b&n%s&r &7has attempted to run a specific command.";
public String dangerousCommandViolation = "&b&n%s&r &7has attempted to run a dangerous command.";
public String loggedCommandViolation = "&b&n%s&r &7has ran a logged command.";
}
public CreativeHotbar creativeHotbar = new CreativeHotbar();
public class CreativeHotbar {
public String nbtAttemptDetection = "A player has attempted to grab an NBT item!";
public String playerInfoTitle = "Player: %s";
public String uuid = "UUID";
public String location = "Location";
public String locationFormat = "X: %s Y: %s Z: %s";
public String itemType = "Type";
public String nbtUpload = "NBT Upload";
public String itemInfoTitle = "Item Info";
public String nbtAttemptViolation = "&b&n%s&r &7has attempted to grab an NBT item.";
}
public ViolationMessages violationMessages = new ViolationMessages();
public class ViolationMessages {
public String actions = "Actions";
public String eventCancelled = "Canceled Event";
public String punishmentCommandsExecuted = "Executed Punishment Commands";
public String userOpStripped = "Stripped user's OP";
public String loggedToDiscord = "Logged to Discord";
}
}
}

View File

@@ -0,0 +1,7 @@
package me.trouper.sentinel.data.types;
public enum CMDBlockType {
CHAIN,
REPEAT,
IMPULSE,
}

View File

@@ -0,0 +1,4 @@
package me.trouper.sentinel.data.types;
public record Location(String world, double x, double y,double z) {
}

View File

@@ -0,0 +1,15 @@
package me.trouper.sentinel.data.types;
import org.bukkit.Bukkit;
import org.bukkit.World;
public record WhitelistedBlock(String owner, Location loc, String type, boolean active, String command) {
public static org.bukkit.Location fromSerialized(Location loc) {
World w = Bukkit.getWorld(loc.world());
return new org.bukkit.Location(w,loc.x(),loc.y(),loc.z());
}
public static Location serialize(org.bukkit.Location loc) {
return new Location(loc.getWorld().getName(),loc.x(),loc.y(),loc.z());
}
}

View File

@@ -0,0 +1,50 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import io.github.itzispyder.pdk.utils.misc.Cooldown;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.chatfilter.Report;
import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.UUID;
@CommandRegistry(value = "sentinelcallback", permission = @Permission("sentinel.callbacks"), printStackTrace = true)
public class CallbackCommand implements CustomCommand {
Cooldown<UUID> fpReportCooldown = new Cooldown<>();
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
Player p = (Player) sender;
switch (args.get(0).toString()) {
case "fpreport" -> {
if (fpReportCooldown.isOnCooldown(p.getUniqueId()) && !p.isOp()) {
p.sendMessage(Text.prefix(Sentinel.lang.cooldown.onCooldown + fpReportCooldown.getCooldown(p.getUniqueId())));
} else {
long id = args.get(1).toLong();
Report report = FalsePositiveReporting.reports.get(id);
if (report == null) {
p.sendMessage(Text.prefix(Sentinel.lang.reports.noReport));
return;
}
p.sendMessage(Text.prefix(Sentinel.lang.reports.reportingFalsePositive));
FalsePositiveReporting.sendReport(p,report);
p.sendMessage(Text.prefix(Sentinel.lang.reports.falsePositiveSuccess));
}
}
}
}
@Override
public void dispatchCompletions(CommandSender sender, Command command, String s, CompletionBuilder b) {
}
}

View File

@@ -0,0 +1,54 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.Message;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
@CommandRegistry(value = "sentinelmessage",permission = @Permission("sentinel.message"))
public class MessageCommand implements CustomCommand {
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
Player p = (Player) sender;
Player r = null;
if (args.getSize() == 0) {
p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noOnlinePlayer));
return;
}
if (args.getSize() == 1) {
p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noMessageProvided));
return;
}
r = Bukkit.getPlayer(args.get(0).toString());
String msg = args.getAll(1).toString().trim();
if (p.hasPermission("sentinel.message") && r != null) {
Message.messagePlayer(p,r,msg);
} else if (r == null) p.sendMessage(Text.prefix((Sentinel.lang.playerInteraction.noOnlinePlayer)));
else sender.sendMessage(Text.prefix(Sentinel.lang.permissions.noPermission));
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
List<String> players = new ArrayList<>();
Bukkit.getOnlinePlayers().forEach(
player -> {
players.add(player.getName());
}
);
b.then(b.arg(players)
.then(b.arg("[<Message>]")));
}
}

View File

@@ -0,0 +1,39 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandRegistry(value = "reop")
public class ReopCommand implements CustomCommand {
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
Player p = (Player) sender;
if (PlayerUtils.isTrusted(p) && Sentinel.mainConfig.plugin.reopCommand) {
if (!p.isOp()) {
p.sendMessage(Text.prefix(Sentinel.lang.permissions.elevatingPerms));
Sentinel.log.info(Sentinel.lang.permissions.logElevatingPerms.formatted(p.getName()));
p.setOp(true);
} else {
p.sendMessage(Text.prefix(Sentinel.lang.permissions.alreadyOp));
Sentinel.log.info(Sentinel.lang.permissions.logAlreadyOp.formatted(p.getName()));
p.setOp(true);
}
} else {
p.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
}
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder completionBuilder) {
}
}

View File

@@ -0,0 +1,49 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.Message;
import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.UUID;
@CommandRegistry(value = "reply", permission = @Permission("sentinel.reply"))
public class ReplyCommand implements CustomCommand {
public static Map<UUID, UUID> replyMap = Message.replyMap;
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
String name = sender.getName();
Player p = sender.getServer().getPlayer(name);
UUID senderID = p.getUniqueId();
if (replyMap.get(senderID) == null) {
p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noReply));
}
Player r = sender.getServer().getPlayer(replyMap.get(senderID));
UUID reciverID = r.getUniqueId();
if (args.get(0).toString() == null) {
p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noMessageProvided));
}
String msg = args.getAll().toString();
if (p.hasPermission("sentinel.message")) {
Message.messagePlayer(p,r,msg);
replyMap.put(senderID,reciverID);
} else {
sender.sendMessage(Text.prefix(Sentinel.lang.permissions.noPermission));
}
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
b.then(b.arg("[<Message>]"));
}
}

View File

@@ -0,0 +1,241 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.regex.AntiRegex;
import me.trouper.sentinel.server.functions.chatfilter.profanity.AntiProfanity;
import me.trouper.sentinel.server.functions.chatfilter.spam.AntiSpam;
import me.trouper.sentinel.data.config.MainConfig;
import me.trouper.sentinel.server.functions.CBWhitelistManager;
import me.trouper.sentinel.data.types.WhitelistedBlock;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.startup.Auth;
import me.trouper.sentinel.startup.Load;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.Text;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.Node;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.Set;
import java.util.UUID;
@CommandRegistry(value = "sentinel",permission = @Permission("sentinel.staff"),printStackTrace = true)
public class SentinelCommand implements CustomCommand {
public static String liteMode = Text.color("""
&8]=-&f Welcome to &d&lSentinel &7|&f Anti-Nuke &8-=[
&7The plugin is currently loaded in &clite&7 mode.
&7Your License Key is &a%s&7.
&7Your server ID is &6%s&7.
&7You are &6%s&7.
&fIf you have just &apurchased&f the plugin:
&8- &7Join the &b&ndiscord&r&7 and open a ticket.
&8- &7https://discord.gg/Xh6BAzNtxY
&8- &7You will then receive a license key.
&fIf you have &cnot&f purchased the plugin:
&8- &7Then purchase it :D
&8- &7It wont do anything in this state!
&8- &7(Its only 5$)
&fIf you are reading this from a decompiler:
&8- &7Please stop trying to crack the plugin and purchase it!
&8- &7Your time spent trying trying to bypass my DRM could be spent at a minimum wage job.
&8- &7There you will make 7$ an hour! (As oppose to 5$ for multiple hours of cracking)
&fWoah! You read quite far!
&8- &7Want the plugin for cheaper, &nor even for free&r&7?
&8- &7DM &b@obvwolf&7 on discord and lets make a deal!
""".formatted(Auth.getLicenseKey(),Auth.getServerID(), MainConfig.username));
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
if (Load.lite) {
if (!args.isEmpty() && args.get(0).toString().equals("reload")) {
if (!(sender instanceof ConsoleCommandSender) && !PlayerUtils.isTrusted((Player) sender)) {
sender.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
return;
}
Sentinel.log.info("Sentinel is now Reloading the config.");
sender.sendMessage(Text.prefix("Reloading the config."));
Sentinel.loadConfig();
String serverID = Auth.getServerID();
String license = Sentinel.mainConfig.plugin.license;
String nonce = Auth.getNonce();
Auth.getPort();
Sentinel.log.info("\n]====---- Requesting Authentication ----====[ \n- License Key: %s\n- Server ID: %s\n- Nonce: %s\n".formatted(license, serverID, nonce));
if (Auth.canLoad()) {
Load.startup(false);
return;
}
Sentinel.log.info("Re-authentication Failed.");
} else {
sender.sendMessage(liteMode);
}
return;
}
if (args.getSize() > 0 == args.get(0).toString().equals("reload")) {
if (sender instanceof Player p) {
if (!PlayerUtils.isTrusted(p)) {
p.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
return;
}
}
Sentinel.log.info("Sentinel is now Reloading the config.");
sender.sendMessage(Text.prefix("Reloading the config."));
Sentinel.loadConfig();
}
Player p = (Player) sender;
if (!p.hasPermission("sentinel.staff")) return;
switch (args.get(0).toString()) {
case "config" -> {
if (!PlayerUtils.isTrusted(p)) return;
if (!MainGUI.verify(p)) return;
p.openInventory(new MainGUI().home.getInventory());
}
case "commandblock", "cb" -> handleCommandBlock(p,args);
case "debug" -> handleDebugCommand(p,args);
case "false-positive" -> handleFalsePositive(p,args);
}
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
b.then(b.arg("config"));
b.then(b.arg("reload"));
b.then(b.arg("false-positive").then(b.arg("add","remove")));
b.then(b.arg("debug").then(
b.arg("lang","toggle","chat")));
b.then(b.arg("commandblock","cb").then(b.arg("add","remove","auto"))
.then(b.arg("restore")
.then(b.arg("<player>","all")))
.then(b.arg("clear")
.then(b.arg("<player>","all"))));
}
private void handleFalsePositive(Player p, Args args) {
if (!p.hasPermission("sentinel.chat.antiswear.edit")) {
p.sendMessage(Sentinel.lang.permissions.noPermission);
return;
}
String falsePositive = args.getAll(2).toString();
Node root = new Node("Sentinel");
root.addTextLine("False Positive Management Log");
Node info = new Node("Info");
info.addKeyValue("User",p.getName());
switch (args.get(1).toString()) {
case "add" -> {
Sentinel.fpConfig.swearWhitelist.add(falsePositive);
p.sendMessage(Text.prefix("&7Successfully added &a%s&7 to the false positive list!".formatted(falsePositive)));
info.addKeyValue("Action","Add");
}
case "remove" -> {
Sentinel.fpConfig.swearWhitelist.remove(falsePositive);
p.sendMessage(Text.prefix("&7Successfully removed &c%s&7 from the false positive list!".formatted(falsePositive)));
info.addKeyValue("Action","Remove");
}
}
info.addKeyValue("False Positive Edited", falsePositive);
root.addChild(info);
Sentinel.fpConfig.save();
Sentinel.log.info(ConsoleFormatter.format(root));
EmbedFormatter.sendEmbed(EmbedFormatter.format(root));
}
private void handleCommandBlock(Player p, Args args) {
if (!PlayerUtils.isTrusted(p)) {
p.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
return;
}
Block target = p.getTargetBlock(Set.of(Material.AIR),10);
switch (args.get(1).toString()) {
case "add" -> {
if (target.getType().equals(Material.COMMAND_BLOCK) || target.getType().equals(Material.REPEATING_COMMAND_BLOCK) || target.getType().equals(Material.CHAIN_COMMAND_BLOCK)) {
CommandBlock cb = (CommandBlock) target.getState();
CBWhitelistManager.add(cb,p.getUniqueId());
return;
}
p.sendMessage(Text.prefix("Could not whitelist the &b" + Text.cleanName(target.getType().toString()) + "&7 it is not a command block!"));
}
case "remove" -> {
WhitelistedBlock wb = CBWhitelistManager.get(target.getLocation());
if (wb != null) {
CBWhitelistManager.remove(target.getLocation());
p.sendMessage(Text.prefix("Successfully removed 1 &b" + Text.cleanName(WhitelistedBlock.fromSerialized(wb.loc()).getBlock().getType().toString()) + "&7 with the command &a" + wb.command() + "&7."));
return;
}
p.sendMessage(Text.prefix("Could not un-whitelist the &b" + Text.cleanName(target.getType().toString()) + "&7 it wasn't whitelisted in the first place!"));
}
case "auto" -> {
if (CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) {
CBWhitelistManager.autoWhitelist.remove(p.getUniqueId());
p.sendMessage(Text.prefix("Successfully toggled &bauto whitelist&7 off for you."));
} else {
CBWhitelistManager.autoWhitelist.add(p.getUniqueId());
p.sendMessage(Text.prefix("Successfully toggled &bauto whitelist&7 on for you."));
}
}
case "restore" -> {
if (args.get(2).toString().equals("all")) {
int result = CBWhitelistManager.restoreAll();
p.sendMessage(Text.prefix("Successfully restored &b%s&7 command blocks.".formatted(result)));
return;
}
String who = args.get(2).toString();
UUID id = Bukkit.getOfflinePlayer(who).getUniqueId();
int result = CBWhitelistManager.restoreAll(id);
p.sendMessage(Text.prefix("Successfully restored &b%s&7 command blocks from &e%s&7.".formatted(result,who)));
}
case "clear" -> {
if (args.get(2).toString().equals("all")) {
int result = CBWhitelistManager.clearAll();
p.sendMessage(Text.prefix("Successfully cleared &b%s&7 command blocks.".formatted(result)));
return;
}
String who = args.get(2).toString();
UUID id = Bukkit.getOfflinePlayer(who).getUniqueId();
int result = CBWhitelistManager.clearAll(id);
p.sendMessage(Text.prefix("Successfully cleared &b%s&7 command blocks from &e%s&7.".formatted(result,who)));
}
}
}
private void handleDebugCommand(Player p, Args args) {
if (!PlayerUtils.isTrusted(p)) {
p.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
return;
}
switch (args.get(1).toString()) {
case "lang" -> {
p.sendMessage(Sentinel.lang.brokenLang);
}
case "toggle" -> {
Sentinel.mainConfig.debugMode = !Sentinel.mainConfig.debugMode ;
p.sendMessage(Text.prefix((Sentinel.mainConfig.debugMode ? "Enabled" : "Disabled") + " debug mode."));
Sentinel.mainConfig.save();
}
case "chat" -> {
AsyncPlayerChatEvent message = new AsyncPlayerChatEvent(true,p,args.getAll(2).toString(), Set.of(p));
AntiRegex.handleRegex(message);
AntiSpam.handleAntiSpam(message);
AntiProfanity.handleProfanityFilter(message);
if (!message.isCancelled()) p.sendMessage(Text.prefix("Message did not get flagged."));
}
}
}
}

View File

@@ -0,0 +1,37 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class SocialSpyCommand implements CustomCommand {
public static Map<UUID, Boolean> spyMap = new HashMap<>();
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
String name = sender.getName();
Player p = sender.getServer().getPlayer(name);
UUID senderID = p.getUniqueId();
if (!spyMap.containsKey(senderID) || !spyMap.get(senderID)) {
sender.sendMessage(Text.prefix(Sentinel.lang.socialSpy.enabled));
spyMap.put(senderID,true);
} else if (spyMap.get(senderID)) {
sender.sendMessage(Text.prefix(Sentinel.lang.socialSpy.disabled));
spyMap.put(senderID,false);
}
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder completionBuilder) {
}
}

View File

@@ -0,0 +1,31 @@
package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.List;
@CommandRegistry(value = "sentineltab")
public class TrapCommand implements CustomCommand {
@Override
public void dispatchCommand(CommandSender commandSender, Command command, String s, Args args) {
commandSender.sendMessage(Component.text(Text.prefix("https://www.youtube.com/watch?v=4F4qzPbcFiA")).clickEvent(ClickEvent.openUrl("https://www.youtube.com/watch?v=4F4qzPbcFiA")));
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
ServerUtils.verbose("Listing the fake plugins: %s".formatted(Sentinel.advConfig.fakePlugins));
b.then(b.arg(Sentinel.advConfig.fakePlugins));
}
}

View File

@@ -0,0 +1,69 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.CBWhitelistManager;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.server.functions.ViolationController;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.CommandBlock;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityChangeBlockEvent;
public class CBEditEvent implements CustomListener {
@EventHandler
private void onCMDBlockChange(EntityChangeBlockEvent e) {
ServerUtils.verbose("CommandBlockChange: Detected the event");
if (!Sentinel.violationConfig.commandBlockEdit.enabled) return;
ServerUtils.verbose("CommandBlockChange: Enabled");
if (!(e.getEntity() instanceof Player p)) return;
ServerUtils.verbose("CommandBlockChange: Changer is a player");
Block b = e.getBlock();
if (!(b.getType() == Material.COMMAND_BLOCK || b.getType() == Material.REPEATING_COMMAND_BLOCK || b.getType() == Material.CHAIN_COMMAND_BLOCK))
return;
ServerUtils.verbose("CommandBlockChange: Block is a command block");
BlockState state = b.getState();
CommandBlock cb = (CommandBlock) state;
if (PlayerUtils.isTrusted(p)) {
if (!CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) return;
CBWhitelistManager.add(cb, p.getUniqueId());
return;
}
ServerUtils.verbose("CommandBlockChange: Not trusted, performing action");
e.setCancelled(true);
Node root = getLog(p, cb);
ViolationController.handleViolation(
"&b&n%s&r &7%s".formatted(p.getName(), Sentinel.lang.violations.commandBlockEdit.playerAttemptEdit),
Sentinel.violationConfig.commandBlockEdit.punish,
Sentinel.violationConfig.commandBlockEdit.deop,
Sentinel.violationConfig.commandBlockEdit.logToDiscord,
p,
Sentinel.violationConfig.commandBlockEdit.punishmentCommands,
root
);
}
private static Node getLog(Player p, CommandBlock cb) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandBlockEdit.playerAttemptEdit);
Node playerInfo = new Node(Sentinel.lang.violations.commandBlockEdit.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.commandBlockEdit.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.commandBlockEdit.location, "X: %s Y: %s Z: %s".formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.commandBlockEdit.violationInfoTitle);
violationInfo.addField(Sentinel.lang.violations.commandBlockEdit.blockLocation,"World: %s X: %s Y: %s Z: %s".formatted(cb.getWorld().getName(), cb.getX(), cb.getY(), cb.getZ()));
violationInfo.addField(Sentinel.lang.violations.commandBlockEdit.insertedCommand, cb.getCommand());
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,85 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.CBWhitelistManager;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.HoverFormatter;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.FileUtils;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.event.EventHandler;
import org.bukkit.event.server.ServerCommandEvent;
public class CBExecuteEvent implements CustomListener {
@EventHandler
private void commandBlockExecute(ServerCommandEvent e) {
//ServerUtils.verbose("Handling command block event: " + e.getCommand());
if (!Sentinel.violationConfig.commandBlockExecute.enabled) return;
//ServerUtils.verbose("Whitelist not disabled ");
if (!(e.getSender() instanceof BlockCommandSender s)) return;
//ServerUtils.verbose("Sender is command block");
Block cmdBlock = s.getBlock();
if (CBWhitelistManager.canRun(cmdBlock)) return;
ServerUtils.verbose("Command block can't run.");
CommandBlock cb = (CommandBlock) cmdBlock.getState();
Node log = getLog(cb);
Node actions = new Node(Sentinel.lang.violations.commandBlockExecute.actionsTitle);
e.setCancelled(true);
actions.addTextLine(Sentinel.lang.violations.commandBlockExecute.preventExecution);
if (Sentinel.violationConfig.commandBlockExecute.destroyBlock) {
cmdBlock.setType(Material.AIR);
actions.addTextLine(Sentinel.lang.violations.commandBlockExecute.destroyedBlock);
}
if (Sentinel.violationConfig.commandBlockExecute.attemptRestore) {
boolean restored = CBWhitelistManager.restore(cmdBlock.getLocation());
actions.addKeyValue(Sentinel.lang.violations.commandBlockExecute.restore, restored ? Sentinel.lang.violations.commandBlockExecute.restoreSuccess : Sentinel.lang.violations.commandBlockExecute.restoreFailure);
}
if (Sentinel.violationConfig.commandBlockExecute.logToDiscord) actions.addTextLine(Sentinel.lang.violations.commandBlockExecute.loggedToDiscord);
log.addChild(actions);
if (Sentinel.violationConfig.commandBlockExecute.logToDiscord) {
EmbedFormatter.sendEmbed(EmbedFormatter.format(log));
}
ServerUtils.forEachPlayer(trusted -> {
if (PlayerUtils.isTrusted(trusted)) {
trusted.sendMessage(Component.text(Text.prefix("The command block whitelist has been tripped!")).hoverEvent(Component.text(HoverFormatter.format(log)).asHoverEvent()));
}
});
Sentinel.log.info(ConsoleFormatter.format(log));
}
private static Node getLog(CommandBlock cb) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandBlockExecute.commandBlockWhitelistTripped);
Node violationInfo = new Node(Sentinel.lang.violations.commandBlockExecute.commandBlockInfoTitle);
violationInfo.addField(Sentinel.lang.violations.commandBlockExecute.blockLocation,"World: %s X: %s Y: %s Z: %s".formatted(cb.getWorld().getName(), cb.getX(), cb.getY(), cb.getZ()));
String command = cb.getCommand();
if (command.length() <= 128) {
violationInfo.addField(Sentinel.lang.violations.commandBlockExecute.executedCommand, command);
} else {
violationInfo.addKeyValue(Sentinel.lang.violations.commandBlockExecute.executedCommand, FileUtils.createCommandLog(command));
}
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,66 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.server.functions.ViolationController;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEvent;
public class CBMCPlaceEvent implements CustomListener {
@EventHandler
private void onCMDMinecartPlace(PlayerInteractEvent e) {
//ServerUtils.verbose("MinecartCommandPlace: Detected interaction");
if (!Sentinel.violationConfig.commandBlockMinecartPlace.enabled) return;
ServerUtils.verbose("MinecartCommandPlace: Check is enabled");
if (!e.getPlayer().isOp()) return;
ServerUtils.verbose("MinecartCommandPlace: Player is op");
if (e.getItem() == null) return;
ServerUtils.verbose("MinecartCommandPlace: Item isn't null");
if (e.getClickedBlock() == null) return;
ServerUtils.verbose("MinecartCommandPlace: Clicked block isn't null");
if (!e.getItem().getType().equals(Material.COMMAND_BLOCK_MINECART)) return;
ServerUtils.verbose("MinecartCommandPlace: Item is a minecart command");
if (!(e.getClickedBlock().getType() == Material.RAIL || e.getClickedBlock().getType() == Material.POWERED_RAIL || e.getClickedBlock().getType() == Material.ACTIVATOR_RAIL || e.getClickedBlock().getType() == Material.DETECTOR_RAIL)) return;
ServerUtils.verbose("MinecartCommandPlace: Clicked block is a rail");
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
ServerUtils.verbose("MinecartCommandPlace: Not trusted, preforming action");
e.setCancelled(true);
p.getInventory().remove(Material.COMMAND_BLOCK_MINECART);
Node log = getLog(p, e.getClickedBlock());
ViolationController.handleViolation(
Sentinel.lang.violations.commandBlockMinecartPlace.detectionChat.formatted(p.getName()),
Sentinel.violationConfig.commandBlockMinecartPlace.punish,
Sentinel.violationConfig.commandBlockMinecartPlace.deop,
Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord,
p,
Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands,
log
);
}
private static Node getLog(Player p, Block cb) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandBlockMinecartPlace.detectionTree);
Node playerInfo = new Node(Sentinel.lang.violations.commandBlockMinecartPlace.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.commandBlockMinecartPlace.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.commandBlockMinecartPlace.location, Sentinel.lang.violations.commandBlockMinecartPlace.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.commandBlockMinecartPlace.minecartPlaceInfoTitle);
violationInfo.addField(Sentinel.lang.violations.commandBlockMinecartPlace.blockLocation, Sentinel.lang.violations.commandBlockMinecartPlace.blockLocationFormat.formatted(cb.getWorld().getName(), cb.getX(), cb.getY(), cb.getZ()));
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,59 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.server.functions.ViolationController;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEntityEvent;
public class CBMCUseEvent implements CustomListener {
@EventHandler
private void onCMDBlockMinecartUse(PlayerInteractEntityEvent e) {
//ServerUtils.verbose("MinecartCommandUse: Detected Interaction with entity");
if (!Sentinel.violationConfig.commandBlockMinecartUse.enabled) return;
ServerUtils.verbose("MinecartCommandUse: Enabled");
if (!e.getPlayer().isOp()) return;
ServerUtils.verbose("MinecartCommandUse: Player op");
if (e.getRightClicked().getType() != EntityType.COMMAND_BLOCK_MINECART) return;
ServerUtils.verbose("MinecartCommandUse: Entity is minecart command");
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
ServerUtils.verbose("MinecartCommandUse: Not trusted, performing action");
e.setCancelled(true);
Node log = getLog(p, e.getRightClicked());
ViolationController.handleViolation(
Sentinel.lang.violations.commandBlockMinecartUse.detectionChat.formatted(p.getName()),
Sentinel.violationConfig.commandBlockMinecartUse.punish,
Sentinel.violationConfig.commandBlockMinecartUse.deop,
Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord,
p,
Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands,
log
);
}
private static Node getLog(Player p, Entity e) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandBlockMinecartUse.detectionTree);
Node playerInfo = new Node(Sentinel.lang.violations.commandBlockMinecartUse.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.commandBlockMinecartUse.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.commandBlockMinecartUse.location, Sentinel.lang.violations.commandBlockMinecartUse.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.commandBlockMinecartUse.minecartUseInfoTitle);
violationInfo.addField(Sentinel.lang.violations.commandBlockMinecartUse.cartLocation, Sentinel.lang.violations.commandBlockMinecartUse.cartLocationFormat.formatted(e.getWorld().getName(), e.getX(), e.getY(), e.getZ()));
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,75 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.CBWhitelistManager;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.FileUtils;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.server.functions.ViolationController;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockPlaceEvent;
public class CBPlaceEvent implements CustomListener {
@EventHandler
private void onCMDBlockPlace(BlockPlaceEvent e) {
//ServerUtils.verbose("CommandBlockPlace: Detected block place");
if (!Sentinel.violationConfig.commandBlockPlace.enabled) return;
ServerUtils.verbose("CommandBlockPlace: Enabled");
if (!e.getPlayer().isOp()) return;
ServerUtils.verbose("CommandBlockPlace: Player is operator");
Block b = e.getBlockPlaced();
if (!(b.getType().equals(Material.COMMAND_BLOCK) ||
b.getType().equals(Material.REPEATING_COMMAND_BLOCK) ||
b.getType().equals(Material.CHAIN_COMMAND_BLOCK))) return;
ServerUtils.verbose("CommandBlockPlace: Block is a command block");
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) {
if (!CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) return;
CBWhitelistManager.add((CommandBlock) b.getState(), p.getUniqueId());
return;
}
ServerUtils.verbose("CommandBlockPlace: Not trusted, performing action");
e.setCancelled(true);
Node log = getLog(p, (CommandBlock) b.getState());
ViolationController.handleViolation(
Sentinel.lang.violations.commandBlockPlace.detectionChat.formatted(p.getName()),
Sentinel.violationConfig.commandBlockPlace.punish,
Sentinel.violationConfig.commandBlockPlace.deop,
Sentinel.violationConfig.commandBlockPlace.logToDiscord,
p,
Sentinel.violationConfig.commandBlockPlace.punishmentCommands,
log
);
}
private static Node getLog(Player p, CommandBlock cb) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandBlockPlace.detectionTree);
Node playerInfo = new Node(Sentinel.lang.violations.commandBlockPlace.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.commandBlockPlace.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.commandBlockPlace.location, Sentinel.lang.violations.commandBlockPlace.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.commandBlockPlace.commandBlockEditInfoTitle);
violationInfo.addField(Sentinel.lang.violations.commandBlockPlace.blockLocation, Sentinel.lang.violations.commandBlockPlace.blockLocationFormat.formatted(cb.getWorld().getName(), cb.getX(), cb.getY(), cb.getZ()));
String command = cb.getCommand();
if (command.length() <= 128) {
violationInfo.addField(Sentinel.lang.violations.commandBlockPlace.insertedCommand, command);
} else {
violationInfo.addKeyValue(Sentinel.lang.violations.commandBlockPlace.insertedCommandUploadedTo, FileUtils.createCommandLog(command));
}
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,80 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.CBWhitelistManager;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.FileUtils;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.server.functions.ViolationController;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEvent;
public class CBUseEvent implements CustomListener {
@EventHandler
private void onCMDBlockUse(PlayerInteractEvent e) {
//ServerUtils.verbose("CommandBlockUse: Detected Interaction");
if (!Sentinel.violationConfig.commandBlockUse.enabled) return;
ServerUtils.verbose("CommandBlockUse: Enabled");
if (!e.getPlayer().isOp()) return;
ServerUtils.verbose("CommandBlockUse: Player is op");
if (e.getClickedBlock() == null) return;
ServerUtils.verbose("CommandBlockUse: Block isn't null");
Block b = e.getClickedBlock();
if (!(b.getType() == Material.COMMAND_BLOCK || b.getType() == Material.REPEATING_COMMAND_BLOCK || b.getType() == Material.CHAIN_COMMAND_BLOCK)) return;
CommandBlock cb = (CommandBlock) b.getState();
ServerUtils.verbose("CommandBlockUse: Block is a command block");
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) {
if (!CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) return;
if (CBWhitelistManager.canRun(cb.getBlock())) return;
e.setCancelled(true);
CBWhitelistManager.add(cb, p.getUniqueId());
return;
}
ServerUtils.verbose("CommandBlockUse: Not trusted, performing action");
e.setCancelled(true);
Node log = getLog(p, (CommandBlock) b.getState());
ViolationController.handleViolation(
Sentinel.lang.violations.commandBlockUse.detectionChat.formatted(p.getName()),
Sentinel.violationConfig.commandBlockUse.punish,
Sentinel.violationConfig.commandBlockUse.deop,
Sentinel.violationConfig.commandBlockUse.logToDiscord,
p,
Sentinel.violationConfig.commandBlockUse.punishmentCommands,
log
);
}
private static Node getLog(Player p, CommandBlock cb) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandBlockUse.detectionTree);
Node playerInfo = new Node(Sentinel.lang.violations.commandBlockUse.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.commandBlockUse.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.commandBlockUse.location, Sentinel.lang.violations.commandBlockUse.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.commandBlockUse.commandBlockUseInfoTitle);
violationInfo.addField(Sentinel.lang.violations.commandBlockUse.blockLocation, Sentinel.lang.violations.commandBlockUse.blockLocationFormat.formatted(cb.getWorld().getName(), cb.getX(), cb.getY(), cb.getZ()));
String command = cb.getCommand();
if (command.length() <= 128) {
violationInfo.addField(Sentinel.lang.violations.commandBlockUse.commandInside, command);
} else {
violationInfo.addKeyValue(Sentinel.lang.violations.commandBlockUse.commandUploadedTo, FileUtils.createCommandLog(command));
}
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,100 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.regex.AntiRegex;
import me.trouper.sentinel.server.functions.chatfilter.profanity.AntiProfanity;
import me.trouper.sentinel.server.functions.chatfilter.spam.AntiSpam;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.chat.ProfanityFilterGUI;
import me.trouper.sentinel.server.gui.config.chat.RegexFilterGUI;
import me.trouper.sentinel.server.gui.config.chat.SpamFilterGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.*;
import me.trouper.sentinel.server.gui.config.nuke.checks.command.DangerousCMDGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.command.LoggedCMDGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.command.SpecificCMDGUI;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.function.Consumer;
public class ChatEvent implements CustomListener {
@EventHandler
private void onChat(AsyncPlayerChatEvent e) {
ServerUtils.verbose("Chat event sanity check:\n Canceled %s".formatted(e.isCancelled()));
handleEvent(e);
}
public static void handleEvent(AsyncPlayerChatEvent e) {
if (e.isCancelled()) return;
if (PlayerUtils.isTrusted(e.getPlayer().getUniqueId().toString())) {
if (MainGUI.awaitingCallback.contains(e.getPlayer().getUniqueId())) {
ServerUtils.verbose("Attempting to cancel events for callback!");
e.setCancelled(true);
MainGUI.awaitingCallback.remove(e.getPlayer().getUniqueId());
}
ServerUtils.verbose("Handling Chat Event for callbacks");
SchedulerUtils.later(0,()->{
RegexFilterGUI.updater.invokeCallbacks(e);
ProfanityFilterGUI.updater.invokeCallbacks(e);
SpamFilterGUI.updater.invokeCallbacks(e);
DangerousCMDGUI.updater.invokeCallbacks(e);
LoggedCMDGUI.updater.invokeCallbacks(e);
SpecificCMDGUI.updater.invokeCallbacks(e);
CBEditGUI.updater.invokeCallbacks(e);
CBMCPlaceGUI.updater.invokeCallbacks(e);
CBMCUseGUI.updater.invokeCallbacks(e);
CBPlaceGUI.updater.invokeCallbacks(e);
CBUseGUI.updater.invokeCallbacks(e);
HotbarActionGUI.updater.invokeCallbacks(e);
});
return;
}
Player p = e.getPlayer();
ServerUtils.verbose("Chat event start after trust check:\n Canceled %s".formatted(e.isCancelled()));
handle(p,
"sentinel.chat.regex.bypass",
Sentinel.mainConfig.chat.useAntiUnicode, "unicode",
e,
AntiRegex::handleRegex);
ServerUtils.verbose("Chat event middle after regex:\n Canceled %s".formatted(e.isCancelled()));
handle(p,
"sentinel.chat.spam.bypass",
Sentinel.mainConfig.chat.spamFilter.enabled,
"spam",
e,
AntiSpam::handleAntiSpam);
ServerUtils.verbose("Chat event middle after spam:\n Canceled %s".formatted(e.isCancelled()));
handle(p,
"sentinel.chat.swear.bypass",
Sentinel.mainConfig.chat.swearFilter.enabled,
"swear",
e,
AntiProfanity::handleProfanityFilter);
ServerUtils.verbose("Chat event ending after swear:\n Canceled %s".formatted(e.isCancelled()));
}
private static void handle(Player p, String permission, boolean isEnabled, String eventType, AsyncPlayerChatEvent e, Consumer<AsyncPlayerChatEvent> handler) {
ServerUtils.verbose("Handeling a chat filter:\n Canceled %s\nType: %s".formatted(e.isCancelled(),eventType));
if (e.isCancelled()) return;
if (p.hasPermission(permission)) return;
ServerUtils.verbose("ChatEvent: Permission bypass failed, checking for " + eventType);
if (!isEnabled) return;
ServerUtils.verbose("ChatEvent: " + eventType + " check enabled, continuing!");
handler.accept(e);
}
}

View File

@@ -0,0 +1,115 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.FileUtils;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.server.functions.ViolationController;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import java.util.HashSet;
import java.util.Set;
public class CommandExecuteEvent implements CustomListener {
@EventHandler
private void onCommand(PlayerCommandPreprocessEvent e) {
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
String label = e.getMessage().substring(1).split(" ")[0];
String args = e.getMessage();
Set<String> status = getCommandStatus(label);
if (status.contains("SPECIFIC") && Sentinel.violationConfig.commandExecute.specific.enabled) {
e.setCancelled(true);
Node log = getLog(p, args, "specific");
ViolationController.handleViolation(
Sentinel.lang.violations.commandExecute.specificCommandViolation.formatted(p.getName()),
Sentinel.violationConfig.commandExecute.specific.punish,
false,
Sentinel.violationConfig.commandExecute.specific.logToDiscord,
p,
Sentinel.violationConfig.commandExecute.specific.punishmentCommands,
log
);
return;
}
if (status.contains("DANGEROUS") && Sentinel.violationConfig.commandExecute.dangerous.enabled) {
e.setCancelled(true);
Node log = getLog(p, args, "dangerous");
ViolationController.handleViolation(
Sentinel.lang.violations.commandExecute.dangerousCommandViolation.formatted(p.getName()),
Sentinel.violationConfig.commandExecute.dangerous.punish,
Sentinel.violationConfig.commandExecute.dangerous.deop,
Sentinel.violationConfig.commandExecute.dangerous.logToDiscord,
p,
Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands,
log
);
return;
}
if (status.contains("LOGGED") && Sentinel.violationConfig.commandExecute.logged.enabled) {
Node log = getLog(p, args, "logged");
ViolationController.handleViolation(
Sentinel.lang.violations.commandExecute.loggedCommandViolation.formatted(p.getName()),
false,
false,
Sentinel.violationConfig.commandExecute.logged.logToDiscord,
p,
null,
log
);
return;
}
}
public static Set<String> getCommandStatus(String label) {
Set<String> commandTypes = new HashSet<>();
if (label.startsWith("/")) {
label = label.substring(1);
}
if (label.contains(":")) {
commandTypes.add("SPECIFIC");
}
for (String loggedCommand : Sentinel.violationConfig.commandExecute.logged.commands) {
if (loggedCommand.equals(label)) commandTypes.add("LOGGED");
}
for (String dangerousCommand : Sentinel.violationConfig.commandExecute.dangerous.commands) {
if (dangerousCommand.equals(label)) commandTypes.add("DANGEROUS");
}
return commandTypes;
}
private Node getLog(Player p, String command, String status) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.commandExecute.specificCommandDetection.formatted(status));
Node playerInfo = new Node(Sentinel.lang.violations.commandExecute.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.commandExecute.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.commandExecute.location, Sentinel.lang.violations.commandExecute.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.commandExecute.violationInfoTitle);
if (command.length() <= 128) {
violationInfo.addField(Sentinel.lang.violations.commandExecute.commandField, command);
} else {
violationInfo.addKeyValue(Sentinel.lang.violations.commandExecute.commandUploadedTo, FileUtils.createCommandLog(command));
}
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,62 @@
package me.trouper.sentinel.server.events;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.ViolationController;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.*;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.inventory.ItemStack;
public class CreativeHotbarEvent implements CustomListener {
@EventHandler
private void onNBTPull(InventoryCreativeEvent e) {
//ServerUtils.verbose("NBT: Detected creative mode action");
if (!Sentinel.violationConfig.creativeHotbarAction.enabled) return;
ServerUtils.verbose("NBT: Enabled");
if (!(e.getWhoClicked() instanceof Player p)) return;
ServerUtils.verbose("NBT: Clicker is a player");
if (e.getCursor() == null) return; // Well it through an exception during testing, so it isn't always false!
ServerUtils.verbose("NBT: Cursor isn't null");
ItemStack i = e.getCursor();
if (PlayerUtils.isTrusted(p)) return;
ServerUtils.verbose("NBT: Not trusted");
if (e.getCursor().getItemMeta() == null) return;
ServerUtils.verbose("NBT: Cursor has meta");
if (!(i.hasItemMeta() && i.getItemMeta() != null)) return;
ServerUtils.verbose("NBT: Item has meta");
if (ItemUtils.itemPasses(i)) return;
ServerUtils.verbose("NBT: Item doesn't pass, performing action");
e.setCancelled(true);
Node root = getLog(p, i);
ViolationController.handleViolation(
Sentinel.lang.violations.creativeHotbar.nbtAttemptViolation.formatted(p.getName()),
Sentinel.violationConfig.creativeHotbarAction.punish,
Sentinel.violationConfig.creativeHotbarAction.deop,
Sentinel.violationConfig.creativeHotbarAction.logToDiscord,
p,
Sentinel.violationConfig.creativeHotbarAction.punishmentCommands,
root
);
}
private static Node getLog(Player p, ItemStack item) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.creativeHotbar.nbtAttemptDetection);
Node playerInfo = new Node(Sentinel.lang.violations.creativeHotbar.playerInfoTitle.formatted(p.getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.creativeHotbar.uuid, p.getUniqueId().toString());
playerInfo.addField(Sentinel.lang.violations.creativeHotbar.location, Sentinel.lang.violations.creativeHotbar.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
root.addChild(playerInfo);
Node violationInfo = new Node(Sentinel.lang.violations.creativeHotbar.itemInfoTitle);
violationInfo.addKeyValue(Sentinel.lang.violations.creativeHotbar.itemType, item.getType().toString());
violationInfo.addField(Sentinel.lang.violations.creativeHotbar.nbtUpload, FileUtils.createNBTLog(item));
root.addChild(violationInfo);
return root;
}
}

View File

@@ -0,0 +1,135 @@
package me.trouper.sentinel.server.events;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerCommandSendEvent;
import org.bukkit.event.server.TabCompleteEvent;
import org.bukkit.plugin.Plugin;
import java.util.List;
public class PluginCloakingEvents implements CustomListener {
@EventHandler
public void onCommand(PlayerCommandPreprocessEvent e) {
if (!Sentinel.doNoPlugins) return;
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
String message = e.getMessage();
if (message.startsWith("/")) {
message = message.substring(1);
}
for (String alias : Sentinel.advConfig.versionAliases) {
if (!message.startsWith(alias)) continue;
e.setCancelled(true);
p.sendMessage(Text.color(Sentinel.lang.permissions.noPlugins));
}
}
@EventHandler
public void onTabComplete(PlayerCommandSendEvent e) {
if (!Sentinel.doNoPlugins) return;
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
List<String> commands = e.getCommands().stream().toList();
for (String command : commands) {
if (command.contains(":")) {
e.getCommands().remove(command);
continue;
}
if (Sentinel.advConfig.versionAliases.contains(command)) {
e.getCommands().remove(command);
continue;
}
}
//ServerUtils.verbose("Removed all the plugin specific commands form the listing. It now contains %s".formatted(e.getCommands().stream().toList().toString()));
for (String fakePlugin : Sentinel.advConfig.fakePlugins) {
e.getCommands().add(fakePlugin + ":" + fakePlugin);
}
//ServerUtils.verbose("Added the fake plugins, now it contains this: %s".formatted(e.getCommands().stream().toList().toString()));
}
public static void registerEvent(Plugin plugin) {
Sentinel.protocolManager.addPacketListener(new PacketAdapter(
plugin,
ListenerPriority.NORMAL,
PacketType.Play.Client.TAB_COMPLETE
) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (!Sentinel.doNoPlugins) return;
if (PlayerUtils.isTrusted(event.getPlayer())) return;
ServerUtils.verbose("Type: §b%s§7 Index 0: §b%s§7".formatted(
event.getPacket().getType(),
event.getPacket().getStrings().read(0)
));
String command = event.getPacket().getStrings().read(0);
if (command.startsWith("/")) command = command.replaceFirst("/","");
ServerUtils.verbose("Command is " + command);
for (String alias : Sentinel.advConfig.versionAliases) {
alias = alias.trim();
command = command.trim();
if (alias.equals(command) || command.startsWith(alias)) {
ServerUtils.verbose("Caught a command we can replace: %s".formatted(command));
event.getPacket().getStrings().write(0,"/sentineltab ");
return;
}
}
}
});
}
/*
Sentinel.protocolManager.addPacketListener(new PacketAdapter(
plugin,
ListenerPriority.NORMAL,
PacketType.Play.Server.COMMANDS
) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (PlayerUtils.isTrusted(event.getPlayer())) return;
ServerUtils.verbose("Index 0: §b%s§7".formatted(
event.getPacket().getStrings().read(0)
));
event.setCancelled(true);
}
});
*/
/*
String input = event.getPacket().getStrings().read(0);
if (input == null || input.isEmpty()) return;
input = input.replaceFirst("/", "");
if (input.length() < 2) {
event.getPacket().getStrings().write(0, "sentineltab");
ServerUtils.verbose("Successfully Blocked ver command: " + input);
return;
}
for (String ver : Sentinel.advConfig.versionAliases) {
if (!input.startsWith(ver + " ")) continue;
String modifiedInput = input.replaceFirst(ver, "sentineltab");
event.getPacket().getStrings().write(0, modifiedInput);
ServerUtils.verbose("Successfully Blocked ver command: " + input);
return;
}
*/
}

View File

@@ -0,0 +1,185 @@
package me.trouper.sentinel.server.functions;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.types.WhitelistedBlock;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
import org.bukkit.persistence.PersistentDataType;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class CBWhitelistManager {
public static Set<UUID> autoWhitelist = new HashSet<>();
public static void add(CommandBlock cb, UUID owner) {
ServerUtils.verbose("Adding a command block to the whitelist.");
boolean alwaysActive = getNBTBoolean(cb, "auto");
WhitelistedBlock wb = new WhitelistedBlock(owner.toString(),WhitelistedBlock.serialize(cb.getLocation()),getType(cb),alwaysActive,cb.getCommand());
Location wbloc = WhitelistedBlock.fromSerialized(wb.loc());
remove(wbloc);
Sentinel.whitelist.whitelistedCMDBlocks.add(wb);
Sentinel.whitelist.save();
if (Bukkit.getPlayer(owner) != null && !Bukkit.getPlayer(owner).isOnline()) return;
Bukkit.getPlayer(owner).sendMessage(Text.prefix("Successfully whitelisted a &b" + Text.cleanName(cb.getType().toString()) + "&7 with the command &a" + cb.getCommand() + "&7."));
}
public static void remove(Location where) {
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
Location cbl = WhitelistedBlock.fromSerialized(cb.loc());
if (cbl.distance(where) < 0.5) {
Sentinel.whitelist.whitelistedCMDBlocks.remove(cb);
}
}
Sentinel.whitelist.save();
}
public static boolean canRun(Block b) {
CommandBlock test = (CommandBlock) b.getState();
String command = test.getCommand();
boolean alwaysActive = getNBTBoolean(test, "auto");
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
if (!(b.getLocation().distance(WhitelistedBlock.fromSerialized(cb.loc())) < 0.5)) continue;
if (cb.active() != alwaysActive) return false;
if (!cb.command().equals(command)) return false;
if (!cb.type().equals(getType(test))) return false;
return PlayerUtils.isTrusted(cb.owner());
}
return false;
}
public static WhitelistedBlock get(Location where) {
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
Location cbl = WhitelistedBlock.fromSerialized(cb.loc());
if (cbl.distance(where) < 0.5) {
return cb;
}
}
return null;
}
public static int clearAll() {
int total = 0;
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
Location remove = WhitelistedBlock.fromSerialized(cb.loc());
remove(remove);
remove.getBlock().setType(Material.AIR);
total++;
}
return total;
}
public static int clearAll(UUID who) {
int total = 0;
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
if (!cb.owner().equals(who.toString())) continue;
Location remove = WhitelistedBlock.fromSerialized(cb.loc());
remove(remove);
remove.getBlock().setType(Material.AIR);
total++;
}
return total;
}
public static int restoreAll() {
int total = 0;
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
if (restore(WhitelistedBlock.fromSerialized(cb.loc()))) total++;
}
return total;
}
public static int restoreAll(UUID who) {
int total = 0;
for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
if (!cb.owner().equals(who.toString())) continue;
if (restore(WhitelistedBlock.fromSerialized(cb.loc()))) total++;
}
return total;
}
public static boolean restore(Location where) {
WhitelistedBlock wb = get(where);
if (wb == null) {
ServerUtils.verbose("No whitelisted command block found at the specified location.");
return false;
}
Block block = where.getBlock();
block.setType(getBlockType(wb.type()));
if (!(block.getState() instanceof CommandBlock)) {
ServerUtils.verbose("Block at the location was not a command block (You shouldn't be seeing this. Report it).");
return false;
}
CommandBlock cb = (CommandBlock) block.getState();
cb.setCommand(wb.command());
cb.setType(getBlockType(wb.type()));
setNBTBoolean(cb, "auto", wb.active());
cb.update();
ServerUtils.verbose("Command block at " + where.toString() + " has been restored.");
return true;
}
public static String getType(CommandBlock cb) {
switch (cb.getType()) {
case COMMAND_BLOCK -> {
return "impulse";
}
case REPEATING_COMMAND_BLOCK -> {
return "repeat";
}
case CHAIN_COMMAND_BLOCK -> {
return "chain";
}
}
return null;
}
private static Material getBlockType(String type) {
return switch (type) {
case "impulse" -> Material.COMMAND_BLOCK;
case "repeat" -> Material.REPEATING_COMMAND_BLOCK;
case "chain" -> Material.CHAIN_COMMAND_BLOCK;
default -> throw new IllegalArgumentException("Unknown command block type: " + type);
};
}
private static void setNBTBoolean(CommandBlock cmdBlock, String key, boolean value) {
cmdBlock.getPersistentDataContainer().set(
getKey(key),
PersistentDataType.BYTE,
value ? (byte) 1 : (byte) 0
);
}
private static boolean getNBTBoolean(CommandBlock cmdBlock, String key) {
return cmdBlock.getPersistentDataContainer().has(
getKey(key),
PersistentDataType.BYTE
) && cmdBlock.getPersistentDataContainer().get(
getKey(key),
PersistentDataType.BYTE
) == 1;
}
private static NamespacedKey getKey(String key) {
return new NamespacedKey(Sentinel.getInstance(), key);
}
}

View File

@@ -0,0 +1,45 @@
package me.trouper.sentinel.server.functions;
import io.github.itzispyder.pdk.utils.ServerUtils;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.commands.SocialSpyCommand;
import me.trouper.sentinel.server.events.ChatEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
public class Message {
public static final Map<UUID,UUID> replyMap = new HashMap<>();
public static void messagePlayer(Player sender, Player receiver, String message) {
HashSet<Player> receivers = new HashSet<>();
receivers.add(receiver);
receivers.add(sender);
AsyncPlayerChatEvent checkEvent = new AsyncPlayerChatEvent(true,sender,message,receivers);
if (checkEvent.isCancelled()) return;
ChatEvent.handleEvent(checkEvent);
if (checkEvent.isCancelled()) return;
sender.sendMessage(Sentinel.lang.playerInteraction.messageSent.formatted(receiver.getName(),message));
receiver.sendMessage(Sentinel.lang.playerInteraction.messageReceived.formatted(sender.getName(),message));
replyMap.put(receiver.getUniqueId(),sender.getUniqueId());
sendSpy(sender,receiver,message);
}
public static void sendSpy(Player sender, Player receiver, String message) {
ServerUtils.forEachPlayer(player -> {
if (SocialSpyCommand.spyMap.getOrDefault(player.getUniqueId(),false)) {
TextComponent notification = Component
.text(Sentinel.lang.socialSpy.spyMessage.formatted(sender.getName(),receiver.getName()))
.hoverEvent(Component.text(Sentinel.lang.socialSpy.spyMessageHover.formatted(sender.getName(),receiver.getName(),message)));
player.sendMessage(notification);
}
});
}
}

View File

@@ -0,0 +1,78 @@
package me.trouper.sentinel.server.functions;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Randomize items from a list
* @param <T> list of?
*/
public class Randomizer<T> {
public static long generateID() {
Date now = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String formattedDate = dateFormat.format(now);
long id = Long.parseLong(formattedDate);
return id;
}
private final List<T> array;
/**
* From array list
* @param array list
*/
public Randomizer(List<T> array) {
this.array = array;
}
/**
* From set
* @param array set
*/
public Randomizer(Set<T> array) {
this.array = new ArrayList<>(array);
}
/**
* From array
* @param array array
*/
public Randomizer(T[] array) {
this.array = List.of(array);
}
/**
* Pick random from the array
* @return random of list of?
*/
public T pickRand() {
return array.get(rand(array.size() - 1));
}
/**
* Generates a random integer from 1 to (max)
* @param max max value
* @return random
*/
public static int rand(int max) {
if (max <= 0) throw new IllegalArgumentException("max cannot be less than 1!");
return (int) Math.ceil(Math.random() * max);
}
/**
* Generates a random integer from (min) to (max)
* @param min min value
* @param max max value
* @return random
*/
public static int rand(int min, int max) {
if (max <= 0 || min <= 0) throw new IllegalArgumentException("max or min cannot be less than 1!");
if (max <= min) throw new IllegalArgumentException("max cannot be less than or equal to min!");
return min + (int) Math.floor(Math.random() * (max - min + 1));
}
}

View File

@@ -0,0 +1,50 @@
package me.trouper.sentinel.server.functions;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.HoverFormatter;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import java.util.List;
public class ViolationController {
public static void handleViolation(String message, boolean punish, boolean deopUser, boolean logToDiscord, Player perp, List<String> punishCommands, Node tree) {
Node actions = new Node(Sentinel.lang.violations.violationMessages.actions);
actions.addTextLine(Sentinel.lang.violations.violationMessages.eventCancelled);
if (punish) {
for (String punishCommand : punishCommands) {
ServerUtils.sendCommand(punishCommand.replaceAll("%player%", perp.getName()));
}
actions.addTextLine(Sentinel.lang.violations.violationMessages.punishmentCommandsExecuted);
}
if (deopUser) {
perp.setOp(false);
actions.addTextLine(Sentinel.lang.violations.violationMessages.userOpStripped);
}
if (logToDiscord) actions.addTextLine(Sentinel.lang.violations.violationMessages.loggedToDiscord);
tree.addChild(actions);
if (logToDiscord) {
EmbedFormatter.sendEmbed(EmbedFormatter.format(tree));
}
ServerUtils.forEachPlayer(trusted -> {
if (PlayerUtils.isTrusted(trusted)) {
trusted.sendMessage(Component.text(Text.prefix(message)).hoverEvent(Component.text(HoverFormatter.format(tree)).asHoverEvent()));
}
});
Sentinel.log.info(ConsoleFormatter.format(tree));
}
}

View File

@@ -0,0 +1,53 @@
package me.trouper.sentinel.server.functions.chatfilter;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
import me.trouper.sentinel.data.Emojis;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.server.functions.Randomizer;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class FalsePositiveReporting {
public static Map<Long, Report> reports = new HashMap<>();
public static Report initializeReport(String message) {
final long reportID = Randomizer.generateID();
LinkedHashMap<String,String> steps = new LinkedHashMap<>();
steps.put("Original Message", "`%s`".formatted(message));
SchedulerUtils.later(1200,()->{
reports.remove(reportID);
});
return new Report(reportID,message,steps);
}
public static void sendReport(Player sender, Report report) {
DiscordEmbed.Builder embed = DiscordEmbed.create()
.author(new DiscordEmbed.Author("Anti-Swear False Positive","",null))
.title("A player has reported a false positive")
.desc(String.format("""
%1$sPlayer: %2$s %3$s
%4$s %5$sUUID: `%6$s`
## **Filter Steps Taken:**
""",
Emojis.rightSort,
sender.getName(),
Emojis.target,
Emojis.space,
Emojis.rightArrow,
sender.getUniqueId()
));
report.getStepsTaken().forEach((key, value)->{
embed.addField(new DiscordEmbed.Field(key,value));
});
EmbedFormatter.sendEmbed(embed.build());
reports.remove(report.getId());
}
}

View File

@@ -0,0 +1,87 @@
package me.trouper.sentinel.server.functions.chatfilter;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.profanity.Severity;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
public class FilterHelpers {
public static Severity checkSlur(String text, Severity backup) {
if (containsSlurs(text)) return Severity.SLUR;
if (containsSwears(text)) return backup;
return Severity.SAFE;
}
public static boolean containsSwears(String text) {
ServerUtils.verbose("ProfanityFilter: Checking for swears");
for (String swear : Sentinel.swearConfig.swears) {
if (text.contains(swear)) return true;
}
return false;
}
public static boolean containsSlurs(String text) {
ServerUtils.verbose("ProfanityFilter: Checking for slurs");
for (String slur : Sentinel.strictConfig.strict) {
if (text.contains(slur)) return true;
}
return false;
}
public static String removeFalsePositives(String text) {
for (String falsePositive : Sentinel.fpConfig.swearWhitelist) {
text = text.replace(falsePositive, "");
}
text = text.replaceAll(Sentinel.advConfig.falsePosRegex,"");
return text;
}
public static String convertLeetSpeakCharacters(String text) {
text = Text.fromLeetString(text);
return text;
}
public static String stripSpecialCharacters(String text) {
text = text.replaceAll("[^A-Za-z0-9.,!?;:'\"()\\[\\]{}]", "").trim();
return text;
}
public static String simplifyRepeatingLetters(String text) {
text = Text.replaceRepeatingLetters(text);
return text;
}
public static String removePeriodsAndSpaces(String text) {
return text.replaceAll("[^A-Za-z0-9]", "").replace(" ", "");
}
public static String highlightProfanity(String text, String start, String end) {
String highlightedSwears = highlightSwears(fullSimplify(text), start, end);
return Text.color(highlightSlurs(highlightedSwears, start, end));
}
private static String highlightSwears(String text, String start, String end) {
for (String swear : Sentinel.swearConfig.swears) {
text = text.replace(swear, start + swear + end);
}
return text;
}
private static String highlightSlurs(String text, String start, String end) {
for (String slur : Sentinel.strictConfig.strict) {
text = text.replace(slur, start + slur + end);
}
return text;
}
public static String fullSimplify(String text) {
String lowercasedText = text.toLowerCase();
String cleanedText = FilterHelpers.removeFalsePositives(lowercasedText);
String convertedText = FilterHelpers.convertLeetSpeakCharacters(cleanedText);
String strippedText = FilterHelpers.stripSpecialCharacters(convertedText);
String simplifiedText = FilterHelpers.simplifyRepeatingLetters(strippedText);
return FilterHelpers.removePeriodsAndSpaces(simplifiedText);
}
}

View File

@@ -0,0 +1,40 @@
package me.trouper.sentinel.server.functions.chatfilter;
import java.util.LinkedHashMap;
public class Report {
private long id;
private String original;
private LinkedHashMap<String,String> stepsTaken;
public Report(long id, String original, LinkedHashMap<String, String> stepsTaken) {
this.id = id;
this.original = original;
this.stepsTaken = stepsTaken;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getOriginal() {
return original;
}
public void setOriginal(String original) {
this.original = original;
}
public LinkedHashMap<String, String> getStepsTaken() {
return stepsTaken;
}
public void setStepsTaken(LinkedHashMap<String, String> stepsTaken) {
this.stepsTaken = stepsTaken;
}
}

View File

@@ -0,0 +1,54 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.ServerUtils;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class AntiProfanity {
public static Map<UUID, Integer> scoreMap = new HashMap<>();
public static void handleProfanityFilter(AsyncPlayerChatEvent event) {
if (event.isCancelled()) {
ServerUtils.verbose("Anti Profanity Opening: Event is canceled.");
}
Player player = event.getPlayer();
ProfanityResponse response = ProfanityResponse.generate(event);
Severity severity = response.getSeverity();
ServerUtils.verbose("Response came back, uncertain null.");
if (severity == null) return;
ServerUtils.verbose("Not null, its severity is " + severity);
if (severity.equals(Severity.SAFE)) return;
ServerUtils.verbose("Not null or safe, canceling event");
event.setCancelled(true);
scoreMap.putIfAbsent(player.getUniqueId(), 0);
int previousScore = scoreMap.get(player.getUniqueId());
int newScore = previousScore + severity.getScore();
scoreMap.put(player.getUniqueId(), newScore);
if (newScore > Sentinel.mainConfig.chat.swearFilter.punishScore || Severity.SLUR.equals(severity)) {
response.setPunished(true);
ProfanityAction.run(response);
return;
}
ProfanityAction.run(response);
}
public static void decayScore() {
for (UUID uuid : scoreMap.keySet()) {
int score = scoreMap.get(uuid);
if (score > 0) {
score = score - Sentinel.mainConfig.chat.swearFilter.scoreDecay;
scoreMap.put(uuid, Math.max(0, score));
}
}
}
}

View File

@@ -0,0 +1,92 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.HoverFormatter;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
public class ProfanityAction {
public static void run(ProfanityResponse response) {
FalsePositiveReporting.reports.put(response.getReport().getId(),response.getReport());
Node tree = getTree(response);
if (response.isPunished()) {
punish(response);
discordNotification(tree);
}
staffWarning(response,tree);
playerWarning(response);
consoleLog(tree);
}
public static void punish(ProfanityResponse response) {
if (response.getSeverity().equals(Severity.SLUR)) {
for (String slurCommand : Sentinel.mainConfig.chat.swearFilter.strictPunishCommands) {
ServerUtils.sendCommand(slurCommand.replaceAll("%player%", response.getEvent().getPlayer().getName()));
}
}
for (String swearCommand : Sentinel.mainConfig.chat.swearFilter.swearPunishCommands) {
ServerUtils.sendCommand(swearCommand.replaceAll("%player%", response.getEvent().getPlayer().getName()));
}
}
public static void staffWarning(ProfanityResponse report, Node tree) {
String messageText = Text.prefix("&b&n%s&r &7%s &8(&4%s&7/&c%s&8)".formatted(
report.getEvent().getPlayer().getName(),
report.isPunished() ? Sentinel.lang.violations.chat.profanity.autoPunish : Sentinel.lang.violations.chat.profanity.prevent,
AntiProfanity.scoreMap.getOrDefault(report.getEvent().getPlayer().getUniqueId(), 0),
Sentinel.mainConfig.chat.swearFilter.punishScore
));
String hoverText = HoverFormatter.format(tree);
ServerUtils.forEachStaff(player -> player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent())));
}
public static void playerWarning(ProfanityResponse response) {
String message = Text.prefix(!response.isPunished() ? Sentinel.lang.violations.chat.profanity.preventWarning : Sentinel.lang.violations.chat.profanity.autoPunishWarning);
String hoverText = Sentinel.lang.automatedActions.actionAutomaticReportable;
String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
response.getEvent().getPlayer().sendMessage(Component.text(message)
.hoverEvent(Component.text(hoverText).asHoverEvent())
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
}
public static void consoleLog(Node tree) {
Sentinel.log.info(ConsoleFormatter.format(tree));
}
public static void discordNotification(Node tree) {
DiscordEmbed embed = EmbedFormatter.format(tree);
EmbedFormatter.sendEmbed(embed);
}
private static Node getTree(ProfanityResponse response) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.chat.profanity.treeTitle);
Node playerInfo = new Node(Sentinel.lang.violations.chat.profanity.playerInfoTitle.formatted(response.getEvent().getPlayer().getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.chat.profanity.uuid, response.getEvent().getPlayer().getUniqueId().toString());
playerInfo.addKeyValue(Sentinel.lang.violations.chat.profanity.score, "%s/%s".formatted(AntiProfanity.scoreMap.getOrDefault(response.getEvent().getPlayer().getUniqueId(),0),Sentinel.mainConfig.chat.swearFilter.punishScore));
root.addChild(playerInfo);
Node reportInfo = new Node(Sentinel.lang.violations.chat.profanity.reportInfoTitle);
reportInfo.addField(Sentinel.lang.violations.chat.profanity.originalMessage, response.getOriginalMessage());
reportInfo.addField(Sentinel.lang.violations.chat.profanity.processedMessage, response.getProcessedMessage());
reportInfo.addKeyValue(Sentinel.lang.violations.chat.profanity.severity, response.getSeverity().toString());
root.addChild(reportInfo);
Node actions = new Node(Sentinel.lang.violations.chat.profanity.actionTitle);
actions.addTextLine(Sentinel.lang.violations.chat.profanity.blockAction);
if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.chat.profanity.commandAction);
root.addChild(actions);
return root;
}
}

View File

@@ -0,0 +1,171 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.chatfilter.FilterHelpers;
import me.trouper.sentinel.server.functions.chatfilter.Report;
import me.trouper.sentinel.data.Emojis;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.event.player.AsyncPlayerChatEvent;
public class ProfanityResponse {
private AsyncPlayerChatEvent event;
private String originalMessage;
private String processedMessage;
private Report report;
private Severity severity;
private boolean punished;
public ProfanityResponse(AsyncPlayerChatEvent event, String originalMessage, String processedMessage, Report report, Severity severity, boolean punished) {
this.event = event;
this.originalMessage = originalMessage;
this.processedMessage = processedMessage;
this.report = report;
this.severity = severity;
this.punished = punished;
}
public AsyncPlayerChatEvent getEvent() {
return event;
}
public void setEvent(AsyncPlayerChatEvent event) {
this.event = event;
}
public String getOriginalMessage() {
return originalMessage;
}
public void setOriginalMessage(String originalMessage) {
this.originalMessage = originalMessage;
}
public String getProcessedMessage() {
return processedMessage;
}
public void setProcessedMessage(String processedMessage) {
this.processedMessage = processedMessage;
}
public Report getReport() {
return report;
}
public void setReport(Report report) {
this.report = report;
}
public Severity getSeverity() {
return severity;
}
public void setSeverity(Severity severity) {
this.severity = severity;
}
public boolean isPunished() {
return punished;
}
public void setPunished(boolean punished) {
this.punished = punished;
}
public static ProfanityResponse generate(AsyncPlayerChatEvent e) {
if (e.isCancelled()) {
ServerUtils.verbose("Profanity response opening Event is canceled.");
}
Report report = FalsePositiveReporting.initializeReport(e.getMessage());
Severity severity = Severity.SAFE;
ProfanityResponse response = new ProfanityResponse(e,e.getMessage(),null,report,severity,false);
String text = Text.removeFirstColor(e.getMessage());
response.setOriginalMessage(text);
// 1:
String lowercasedText = text.toLowerCase();
response.getReport().getStepsTaken().put("Lowercased", lowercasedText);
response.setProcessedMessage(FilterHelpers.highlightProfanity(lowercasedText,"<hs>", "<he>"));
ServerUtils.verbose("ProfanityFilter: Lowercased: " + lowercasedText);
// 2:
String cleanedText = FilterHelpers.removeFalsePositives(lowercasedText);
response.getReport().getStepsTaken().put("Remove False Positives", cleanedText);
response.setProcessedMessage(FilterHelpers.highlightProfanity(cleanedText,"<hs>", "<he>"));
ServerUtils.verbose(("ProfanityFilter: Removed False positives: " + cleanedText));
response.setSeverity(FilterHelpers.checkSlur(cleanedText, Severity.LOW));
if (response.getSeverity() != Severity.SAFE) {
response.getReport().getStepsTaken().replace("Remove False Positives", "%s %s".formatted(
FilterHelpers.highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return response;
}
// 4:
String convertedText = FilterHelpers.convertLeetSpeakCharacters(cleanedText);
response.getReport().getStepsTaken().put("Convert LeetSpeak", convertedText);
response.setProcessedMessage(FilterHelpers.highlightProfanity(convertedText,"<hs>", "<he>"));
ServerUtils.verbose(("ProfanityFilter: Leet Converted: " + convertedText));
response.setSeverity(FilterHelpers.checkSlur(convertedText, Severity.MEDIUM_LOW));
if (response.getSeverity() != Severity.SAFE) {
response.getReport().getStepsTaken().replace("Convert LeetSpeak", "%s %s".formatted(
FilterHelpers.highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return response;
}
// 6:
String strippedText = FilterHelpers.stripSpecialCharacters(convertedText);
response.getReport().getStepsTaken().put("Remove Special Characters", strippedText);
response.setProcessedMessage(FilterHelpers.highlightProfanity(strippedText,"<hs>", "<he>"));
ServerUtils.verbose(("ProfanityFilter: Specials Removed: " + strippedText));
response.setSeverity(FilterHelpers.checkSlur(strippedText, Severity.MEDIUM));
if (response.getSeverity() != Severity.SAFE) {
response.getReport().getStepsTaken().replace("Remove Special Characters", "%s %s".formatted(
FilterHelpers.highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return response;
}
// 8:
String simplifiedText = FilterHelpers.simplifyRepeatingLetters(strippedText);
response.getReport().getStepsTaken().put("Remove Repeats", simplifiedText);
response.setProcessedMessage(FilterHelpers.highlightProfanity(simplifiedText,"<hs>", "<he>"));
ServerUtils.verbose(("ProfanityFilter: Removed Repeating: " + simplifiedText));
response.setSeverity(FilterHelpers.checkSlur(simplifiedText, Severity.MEDIUM_HIGH));
if (response.getSeverity() != Severity.SAFE) {
response.getReport().getStepsTaken().replace("Remove Repeats", "%s %s".formatted(
FilterHelpers.highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
return response;
}
// 10:
String finalText = FilterHelpers.removePeriodsAndSpaces(simplifiedText);
response.getReport().getStepsTaken().put("Remove Punctuation", finalText);
response.setProcessedMessage(FilterHelpers.highlightProfanity(finalText,"<hs>", "<he>"));
ServerUtils.verbose(("ProfanityFilter: Remove Punctuation: " + finalText));
response.setSeverity(FilterHelpers.checkSlur(finalText, Severity.HIGH));
if (response.getSeverity() != Severity.SAFE) {
response.getReport().getStepsTaken().replace("Remove Punctuation", "%s %s".formatted(
FilterHelpers.highlightProfanity(cleanedText,"||","||"),
Emojis.alarm));
}
ServerUtils.verbose(("ProfanityFilter: Finished " + finalText));
if (e.isCancelled()) {
ServerUtils.verbose("Profanity response closing: Event is canceled.");
}
return response;
}
}

View File

@@ -0,0 +1,24 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
import me.trouper.sentinel.Sentinel;
public enum Severity {
LOW(Sentinel.mainConfig.chat.swearFilter.lowScore),
MEDIUM_LOW(Sentinel.mainConfig.chat.swearFilter.mediumLowScore),
MEDIUM(Sentinel.mainConfig.chat.swearFilter.mediumScore),
MEDIUM_HIGH(Sentinel.mainConfig.chat.swearFilter.mediumHighScore),
HIGH(Sentinel.mainConfig.chat.swearFilter.highScore),
REGEX(Sentinel.mainConfig.chat.swearFilter.regexScore),
SLUR(Sentinel.mainConfig.chat.swearFilter.highScore),
SAFE(0);
private final int score;
Severity(int score) {
this.score = score;
}
public int getScore() {
return score;
}
}

View File

@@ -0,0 +1,19 @@
package me.trouper.sentinel.server.functions.chatfilter.regex;
import me.trouper.sentinel.utils.ServerUtils;
import org.bukkit.event.player.AsyncPlayerChatEvent;
public class AntiRegex {
public static void handleRegex(AsyncPlayerChatEvent e) {
if (e.isCancelled()) {
ServerUtils.verbose("Regex Filter opening Event is canceled.");
}
ServerUtils.verbose("Handeling advanced");
RegexResponse response = RegexResponse.generate(e);
ServerUtils.verbose("Response got back");
if (response.getFlagType() == null) return;
ServerUtils.verbose("Detection happened");
e.setCancelled(true);
RegexAction.run(response);
}
}

View File

@@ -0,0 +1,90 @@
package me.trouper.sentinel.server.functions.chatfilter.regex;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.chatfilter.profanity.AntiProfanity;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.HoverFormatter;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
public class RegexAction {
public static void run(RegexResponse response) {
FalsePositiveReporting.reports.put(response.getReport().getId(),response.getReport());
Node tree = getTree(response);
if (response.isPunished()) {
punish(response);
discordNotification(tree);
}
staffWarning(response,tree);
playerWarning(response);
consoleLog(tree);
}
public static void punish(RegexResponse response) {
if (response.getFlagType().equals(RegexFlagType.STRICT_BLOCK)) {
for (String slurCommand : Sentinel.mainConfig.chat.swearFilter.strictPunishCommands) {
ServerUtils.sendCommand(slurCommand.replaceAll("%player%", response.getEvent().getPlayer().getName()));
}
}
for (String swearCommand : Sentinel.mainConfig.chat.swearFilter.swearPunishCommands) {
ServerUtils.sendCommand(swearCommand.replaceAll("%player%", response.getEvent().getPlayer().getName()));
}
}
public static void staffWarning(RegexResponse report, Node tree) {
String messageText = Text.prefix("&b&n%s&r &7%s".formatted(
report.getEvent().getPlayer().getName(),
report.isPunished() ? Sentinel.lang.violations.chat.regex.autoPunish : Sentinel.lang.violations.chat.regex.regexTrigger
));
String hoverText = HoverFormatter.format(tree);
ServerUtils.forEachStaff(player -> player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent())));
}
public static void playerWarning(RegexResponse response) {
String message = Text.prefix(response.getFlagType().getBlockMessage()) ;
String hoverText = Sentinel.lang.automatedActions.actionAutomaticReportable;
String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
response.getEvent().getPlayer().sendMessage(Component.text(message)
.hoverEvent(Component.text(hoverText).asHoverEvent())
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
}
public static void consoleLog(Node tree) {
Sentinel.log.info(ConsoleFormatter.format(tree));
}
public static void discordNotification(Node tree) {
DiscordEmbed embed = EmbedFormatter.format(tree);
EmbedFormatter.sendEmbed(embed);
}
private static Node getTree(RegexResponse response) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.chat.regex.treeTitle);
Node playerInfo = new Node(Sentinel.lang.violations.chat.regex.playerInfoTitle.formatted(response.getEvent().getPlayer().getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.chat.regex.uuid, response.getEvent().getPlayer().getUniqueId().toString());
playerInfo.addKeyValue(Sentinel.lang.violations.chat.regex.score, "%s".formatted(AntiProfanity.scoreMap.get(response.getEvent().getPlayer().getUniqueId())));
root.addChild(playerInfo);
Node reportInfo = new Node(Sentinel.lang.violations.chat.regex.reportInfoTitle.formatted(response.getFlagType().getName()));
reportInfo.addField(Sentinel.lang.violations.chat.regex.originalMessage, response.getOriginalMessage());
reportInfo.addField(Sentinel.lang.violations.chat.regex.flaggedMessage, response.getHighlightedMessage());
root.addChild(reportInfo);
Node actions = new Node(Sentinel.lang.violations.chat.regex.actionTitle);
actions.addTextLine(Sentinel.lang.violations.chat.regex.blockAction);
if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.chat.regex.commandAction);
root.addChild(actions);
return root;
}
}

View File

@@ -0,0 +1,27 @@
package me.trouper.sentinel.server.functions.chatfilter.regex;
import me.trouper.sentinel.Sentinel;
public enum RegexFlagType {
URL_BLOCK(Sentinel.lang.violations.chat.regex.urlBlockName, Sentinel.lang.violations.chat.regex.urlBlockMessage),
UNICODE_BLOCK(Sentinel.lang.violations.chat.regex.unicodeBlockName, Sentinel.lang.violations.chat.regex.unicodeBlockMessage),
SWEAR_BLOCK(Sentinel.lang.violations.chat.regex.swearBlockName, Sentinel.lang.violations.chat.regex.swearBlockMessage),
STRICT_BLOCK(Sentinel.lang.violations.chat.regex.strictBlockName, Sentinel.lang.violations.chat.regex.strictBlockMessage);
private String name;
private String blockMessage;
RegexFlagType(String name, String blockMessage) {
}
public String getBlockMessage() {
return blockMessage;
}
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,188 @@
package me.trouper.sentinel.server.functions.chatfilter.regex;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.chatfilter.Report;
import me.trouper.sentinel.data.Emojis;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexResponse {
private AsyncPlayerChatEvent event;
private String originalMessage;
private String highlightedMessage;
private RegexFlagType flagType;
private Report report;
private boolean isPunished;
public RegexResponse(AsyncPlayerChatEvent event, String originalMessage, String highlightedMessage, RegexFlagType flagType, Report report, boolean isPunished) {
this.event = event;
this.originalMessage = originalMessage;
this.highlightedMessage = highlightedMessage;
this.flagType = flagType;
this.report = report;
this.isPunished = isPunished;
}
public AsyncPlayerChatEvent getEvent() {
return event;
}
public void setEvent(AsyncPlayerChatEvent event) {
this.event = event;
}
public String getOriginalMessage() {
return originalMessage;
}
public void setOriginalMessage(String originalMessage) {
this.originalMessage = originalMessage;
}
public String getHighlightedMessage() {
return highlightedMessage;
}
public void setHighlightedMessage(String highlightedMessage) {
this.highlightedMessage = highlightedMessage;
}
public RegexFlagType getFlagType() {
return flagType;
}
public void setFlagType(RegexFlagType flagType) {
this.flagType = flagType;
}
public Report getReport() {
return report;
}
public void setReport(Report report) {
this.report = report;
}
public boolean isPunished() {
return isPunished;
}
public void setPunished(boolean punished) {
isPunished = punished;
}
public static RegexResponse generate(AsyncPlayerChatEvent e) {
if (e.isCancelled()) {
ServerUtils.verbose("Regex response opening Event is canceled.");
}
Report report = FalsePositiveReporting.initializeReport(e.getMessage());
RegexResponse response = new RegexResponse(e,e.getMessage(),null,null,report,false);
String unicode = handleAntiUnicode(e,response.getReport());
String url = handleAntiURL(e,response.getReport());
String strict = handleStrictRegex(e,response.getReport());
String swear = handleSwearRegex(e,response.getReport());
ServerUtils.verbose("All filters have ran without thread error");
if (Sentinel.mainConfig.chat.useAntiUnicode && handleAntiUnicode(e,report) != null) {
response.setHighlightedMessage(unicode);
response.setFlagType(RegexFlagType.UNICODE_BLOCK);
return response;
}
if (Sentinel.mainConfig.chat.useAntiURL && handleAntiURL(e,report) != null) {
response.setHighlightedMessage(url);
response.setFlagType(RegexFlagType.URL_BLOCK);
return response;
}
if (Sentinel.mainConfig.chat.useStrictRegex && handleStrictRegex(e,report) != null) {
response.setHighlightedMessage(strict);
response.setFlagType(RegexFlagType.STRICT_BLOCK);
return response;
}
if (Sentinel.mainConfig.chat.useSwearRegex && handleSwearRegex(e,report) != null) {
response.setPunished(true);
response.setHighlightedMessage(swear);
response.setFlagType(RegexFlagType.SWEAR_BLOCK);
return response;
}
ServerUtils.verbose("Nothing caught, returning the blank response");
return response;
}
public static String handleAntiUnicode(AsyncPlayerChatEvent e, Report report) {
String message = Text.removeFirstColor(e.getMessage());
report.getStepsTaken().put("Anti-Unicode", "`%s`".formatted(message));
ServerUtils.verbose("AdvBlocker: Checking for unicode: " + message);
String nonAllowed = message.replaceAll(Sentinel.advConfig.allowedCharRegex, "").trim();
if (!nonAllowed.isEmpty()) {
ServerUtils.verbose("AdvBlocker: Caught Unicode: " + nonAllowed);
report.getStepsTaken().replace("Anti-Unicode", "`%s` %s".formatted(message, Emojis.alarm));
return Text.regexHighlighter(message,Sentinel.advConfig.allowedCharRegex," > ", " < ");
}
ServerUtils.verbose("Nothing caught, returning null");
return null;
}
public static String handleSwearRegex(AsyncPlayerChatEvent e, Report report) {
String swearRegex = Sentinel.advConfig.swearRegex;
Pattern pattern = Pattern.compile(swearRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(e.getMessage());
report.getStepsTaken().put("Anti-Swear Regex", "`%s`".formatted(e.getMessage()));
if (matcher.find()) {
String highlighted = Text.regexHighlighter(swearRegex,e.getMessage()," > "," < ");
report.getStepsTaken().replace("Anti-Swear Regex", "`%s` %s".formatted(highlighted, Emojis.alarm));
return highlighted;
}
ServerUtils.verbose("Nothing caught, returning null");
return null;
}
public static String handleStrictRegex(AsyncPlayerChatEvent e, Report report) {
String strictRegex = Sentinel.advConfig.strictRegex;
Pattern pattern = Pattern.compile(strictRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(e.getMessage());
report.getStepsTaken().put("Strict Regex", "`%s`".formatted(e.getMessage()));
if (matcher.find()) {
String highlighted = Text.regexHighlighter(strictRegex,e.getMessage()," > "," < ");
report.getStepsTaken().replace("Strict Regex", "`%s` %s".formatted(highlighted, Emojis.alarm));
return highlighted;
}
ServerUtils.verbose("Nothing caught, returning null");
return null;
}
public static String handleAntiURL(AsyncPlayerChatEvent e, Report report) {
String urlRegex = Sentinel.advConfig.urlRegex;
Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(e.getMessage());
//ServerUtils.sendDebugMessage("AdvBlocker: Checking for URLs against regex `%1$s`:%2$s".formatted(urlRegex, e.getMessage()));
report.getStepsTaken().put("Anti-URL", "`%s`".formatted(
e.getMessage()
));
if (matcher.find()) {
String highlighted = Text.regexHighlighter(e.getMessage(),Sentinel.advConfig.urlRegex," > "," < ");
ServerUtils.verbose("AdvBlocker: Caught URL: " + highlighted);
report.getStepsTaken().replace("Anti-URL", "`%s` %s".formatted(highlighted, Emojis.alarm));
return highlighted;
}
ServerUtils.verbose("Nothing caught, returning null");
return null;
}
}

View File

@@ -0,0 +1,73 @@
package me.trouper.sentinel.server.functions.chatfilter.spam;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class AntiSpam {
public static Map<UUID, Integer> heatMap = new HashMap<>();
public static Map<UUID, String> lastMessageMap = new HashMap<>();
public static void handleAntiSpam(AsyncPlayerChatEvent e) {
if (e.isCancelled()) {
ServerUtils.verbose("Anti Spam Opening: Event is canceled.");
}
Player p = e.getPlayer();
String message = Text.removeFirstColor(e.getMessage());
int currentHeat = heatMap.getOrDefault(p.getUniqueId(),0);
SpamResponse response = SpamResponse.generate(e);
lastMessageMap.put(e.getPlayer().getUniqueId(), e.getMessage());
int addHeat = response.getHeatAdded();
ServerUtils.verbose("AntiSpam responded");
response.getReport().getStepsTaken().put("Response came back", "Heat to add: %s".formatted(addHeat));
if (currentHeat > Sentinel.mainConfig.chat.spamFilter.punishHeat) {
e.setCancelled(true);
response.getReport().getStepsTaken().put("Punished user", "Their final heat was %s".formatted(currentHeat));
response.setPunished(true);
SpamAction.run(response);
heatMap.put(p.getUniqueId(), currentHeat + addHeat);
return;
}
if (currentHeat > Sentinel.mainConfig.chat.spamFilter.blockHeat) {
e.setCancelled(true);
response.getReport().getStepsTaken().put("Blocked message", "Their heat is %s".formatted(currentHeat));
SpamAction.run(response);
heatMap.put(p.getUniqueId(), currentHeat + addHeat);
return;
}
if (response.getSimilarity() > Sentinel.mainConfig.chat.spamFilter.blockSimilarity) {
e.setCancelled(true);
response.getReport().getStepsTaken().put("Blocked message", "The similarity was too high! %s".formatted(response.getSimilarity()));
SpamAction.run(response);
heatMap.put(p.getUniqueId(), currentHeat + addHeat);
return;
}
if (e.isCancelled()) {
ServerUtils.verbose("Anti spam closing: Event is canceled.");
}
heatMap.put(p.getUniqueId(),currentHeat + addHeat);
}
public static void decayHeat() {
for (UUID p : heatMap.keySet()) {
int heat = heatMap.getOrDefault(p,0);
if (heat > 0) {
heat = heat - Sentinel.mainConfig.chat.spamFilter.heatDecay;
heatMap.put(p, Math.max(0, heat));
}
}
}
}

View File

@@ -0,0 +1,89 @@
package me.trouper.sentinel.server.functions.chatfilter.spam;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.HoverFormatter;
import me.trouper.sentinel.utils.trees.Node;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
public class SpamAction {
public static void run(SpamResponse response) {
FalsePositiveReporting.reports.put(response.getReport().getId(),response.getReport());
Node tree = getTree(response);
if (response.isPunished()) {
punish(response);
discordNotification(tree);
}
staffWarning(response,tree);
playerWarning(response);
consoleLog(tree);
}
public static void punish(SpamResponse response) {
for (String spamPunishCommand : Sentinel.mainConfig.chat.spamFilter.punishCommands) {
ServerUtils.sendCommand(spamPunishCommand.replaceAll("%player%", response.getEvent().getPlayer().getName()));
}
}
public static void staffWarning(SpamResponse report, Node tree) {
String messageText = Text.prefix("&b&n%s&r &7%s &8(&4%s&7/&c%s&8)".formatted(
report.getEvent().getPlayer().getName(),
report.isPunished() ? Sentinel.lang.violations.chat.spam.autoPunish : Sentinel.lang.violations.chat.spam.spamWarning,
AntiSpam.heatMap.get(report.getEvent().getPlayer().getUniqueId()),
Sentinel.mainConfig.chat.spamFilter.punishHeat
));
String hoverText = HoverFormatter.format(tree);
ServerUtils.forEachStaff(player -> player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent())));
}
public static void playerWarning(SpamResponse response) {
String message = Text.prefix(!response.isPunished() ? Sentinel.lang.violations.chat.spam.preventWarning : Sentinel.lang.violations.chat.spam.autoPunishWarning) ;
String hoverText = Sentinel.lang.automatedActions.actionAutomaticReportable;
String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
response.getEvent().getPlayer().sendMessage(Component.text(message)
.hoverEvent(Component.text(hoverText).asHoverEvent())
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
}
public static void consoleLog(Node tree) {
Sentinel.log.info(ConsoleFormatter.format(tree));
}
public static void discordNotification(Node tree) {
DiscordEmbed embed = EmbedFormatter.format(tree);
EmbedFormatter.sendEmbed(embed);
}
private static Node getTree(SpamResponse response) {
Node root = new Node("Sentinel");
root.addTextLine(Sentinel.lang.violations.chat.spam.treeTitle);
Node playerInfo = new Node(Sentinel.lang.violations.chat.spam.playerInfoTitle.formatted(response.getEvent().getPlayer().getName()));
playerInfo.addKeyValue(Sentinel.lang.violations.chat.spam.uuid, response.getEvent().getPlayer().getUniqueId().toString());
playerInfo.addKeyValue(Sentinel.lang.violations.chat.spam.heat, "%s/%s".formatted(AntiSpam.heatMap.get(response.getEvent().getPlayer().getUniqueId()),Sentinel.mainConfig.chat.spamFilter.punishHeat));
root.addChild(playerInfo);
Node reportInfo = new Node(Sentinel.lang.violations.chat.spam.reportInfoTitle);
reportInfo.addField(Sentinel.lang.violations.chat.spam.previousMessage, response.getPreviousMessage());
reportInfo.addField(Sentinel.lang.violations.chat.spam.currentMessage, response.getCurrentMessage());
reportInfo.addKeyValue(Sentinel.lang.violations.chat.spam.similarity, "%s/%s".formatted((int) Math.round(response.getSimilarity()),Sentinel.mainConfig.chat.spamFilter.blockSimilarity));
root.addChild(reportInfo);
Node actions = new Node(Sentinel.lang.violations.chat.spam.actionTitle);
actions.addTextLine(Sentinel.lang.violations.chat.spam.blockAction);
if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.chat.spam.commandAction);
root.addChild(actions);
return root;
}
}

View File

@@ -0,0 +1,134 @@
package me.trouper.sentinel.server.functions.chatfilter.spam;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.chatfilter.Report;
import me.trouper.sentinel.utils.MathUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import static me.trouper.sentinel.server.functions.chatfilter.spam.AntiSpam.lastMessageMap;
public class SpamResponse {
private AsyncPlayerChatEvent event;
private String currentMessage;
private String previousMessage;
private double similarity;
private int heatAdded;
private Report report;
private boolean punished;
public SpamResponse(AsyncPlayerChatEvent event, String currentMessage, String previousMessage, double similarity, int heatAdded, Report report, boolean punished) {
this.event = event;
this.currentMessage = currentMessage;
this.previousMessage = previousMessage;
this.similarity = similarity;
this.heatAdded = heatAdded;
this.report = report;
this.punished = punished;
}
public static SpamResponse generate(AsyncPlayerChatEvent e) {
if (e.isCancelled()) {
ServerUtils.verbose("Spam response opening: Event is canceled.");
}
Report report = FalsePositiveReporting.initializeReport(e.getMessage());
String message = Text.removeFirstColor(e.getMessage());
String previousMessage = lastMessageMap.getOrDefault(e.getPlayer().getUniqueId(),"/* Placeholder Message from Sentinel */");
SpamResponse response = new SpamResponse(e,e.getMessage(),previousMessage,0,0,report,false);
double similarity = MathUtils.calcSim(message, previousMessage);
response.setSimilarity(similarity);
report.getStepsTaken().put("Calculated Similarity: ","%s".formatted(similarity));
int addHeat = Sentinel.mainConfig.chat.spamFilter.defaultGain;
if (similarity > Sentinel.mainConfig.chat.spamFilter.blockSimilarity) {
addHeat = Sentinel.mainConfig.chat.spamFilter.highGain;
response.getReport().getStepsTaken().put("Similarity is greater than %s%%".formatted(Sentinel.mainConfig.chat.spamFilter.blockSimilarity), "That is %s heat. (Auto-Block due to configured value)".formatted(addHeat));
response.setHeatAdded(addHeat);
return response;
} else if (similarity > 90) {
addHeat = Sentinel.mainConfig.chat.spamFilter.highGain;
response.getReport().getStepsTaken().put("Similarity is greater than 90%", "That is %s heat.".formatted(addHeat));
response.setHeatAdded(addHeat);
return response;
} else if (similarity > 50) {
addHeat = Sentinel.mainConfig.chat.spamFilter.mediumGain;
response.getReport().getStepsTaken().put("Similarity is greater than 50%", "That is %s heat.".formatted(addHeat));
response.setHeatAdded(addHeat);
return response;
} else if (similarity > 25) {
response.getReport().getStepsTaken().put("Similarity is greater than 25%", "That is %s heat.".formatted(addHeat));
addHeat = Sentinel.mainConfig.chat.spamFilter.lowGain;
response.setHeatAdded(addHeat);
return response;
}
report.getStepsTaken().put("Similarity is less than 25%", "That is %s heat.".formatted(addHeat));
response.setHeatAdded(addHeat);
if (e.isCancelled()) {
ServerUtils.verbose("Spam Response Closing: Event is canceled.");
}
return response;
}
public AsyncPlayerChatEvent getEvent() {
return event;
}
public void setEvent(AsyncPlayerChatEvent event) {
this.event = event;
}
public String getCurrentMessage() {
return currentMessage;
}
public void setCurrentMessage(String currentMessage) {
this.currentMessage = currentMessage;
}
public String getPreviousMessage() {
return previousMessage;
}
public void setPreviousMessage(String previousMessage) {
this.previousMessage = previousMessage;
}
public double getSimilarity() {
return similarity;
}
public void setSimilarity(double similarity) {
this.similarity = similarity;
}
public int getHeatAdded() {
return heatAdded;
}
public void setHeatAdded(int heatAdded) {
this.heatAdded = heatAdded;
}
public Report getReport() {
return report;
}
public void setReport(Report report) {
this.report = report;
}
public boolean isPunished() {
return punished;
}
public void setPunished(boolean punished) {
this.punished = punished;
}
}

View File

@@ -0,0 +1,38 @@
package me.trouper.sentinel.server.gui;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.server.gui.config.ChatGUI;
import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
public class ConfigGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Config Home"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(12, Items.ANTI_NUKE_CONFIG,e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.define(14,Items.CHAT_CONFIG,e->{
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.define(26,Items.BACK,e->{
e.getWhoClicked().openInventory(new MainGUI().home.getInventory());
})
.build();
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
MainGUI.verify((Player) e.getWhoClicked());
}
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
}
}

View File

@@ -0,0 +1,226 @@
package me.trouper.sentinel.server.gui;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.startup.Auth;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class Items {
public static final ItemStack BLANK = ItemBuilder.create()
.material(Material.LIGHT_GRAY_STAINED_GLASS_PANE)
.name(Text.color("&7"))
.build();
public static final ItemStack GREEN = ItemBuilder.create()
.material(Material.LIME_STAINED_GLASS_PANE)
.name(Text.color("&7"))
.build();
public static final ItemStack RED = ItemBuilder.create()
.material(Material.RED_STAINED_GLASS_PANE)
.name(Text.color("&7"))
.build();
public static final ItemStack BACK = ItemBuilder.create()
.material(Material.ARROW)
.name(Text.color("&cBack"))
.lore(Text.color("&8&l➥&7 Return to the previous page"))
.build();
public static final ItemStack CREDITS = ItemBuilder.create()
.material(Material.SHIELD)
.name(Text.color("&6&lSentinel &8&l|&f Anti-Nuke"))
.lore(" ")
.lore(Text.color("&bVersion&7: &f%s".formatted(Sentinel.getInstance().getDescription().getVersion())))
.lore(Text.color("&bLicensed to&7: &f%s".formatted(Auth.getNonce())))
.lore(" ")
.lore(Text.color("&e&nAuthor(s)&r&e: &e%s").formatted(Sentinel.getInstance().getDescription().getAuthors()))
.enchant(Enchantment.PROTECTION,64)
.flag(ItemFlag.HIDE_ENCHANTS)
.build();
public static final ItemStack CONFIG = ItemBuilder.create()
.material(Material.PISTON)
.name(Text.color("&6&lEdit Config"))
.lore(Text.color("&8&l➥&7 Click this if you hate JSON."))
.enchant(Enchantment.PROTECTION,64)
.flag(ItemFlag.HIDE_ENCHANTS)
.build();
public static final ItemStack CHAT_CONFIG = ItemBuilder.create()
.material(Material.HOPPER)
.name(Text.color("&bChat Config"))
.lore(Text.color("&8&l➥&7 Spam Filter"))
.lore(Text.color("&8&l➥&7 Profanity Filter"))
.lore(Text.color("&8&l➥&7 Regex Filters"))
.enchant(Enchantment.PROTECTION,64)
.flag(ItemFlag.HIDE_ENCHANTS)
.build();
public static final ItemStack ANTI_NUKE_CONFIG = ItemBuilder.create()
.material(Material.TNT)
.name(Text.color("&cAnti-Nuke Config"))
.lore(Text.color("&8&l➥&7 Command Block Whitelist"))
.lore(Text.color("&8&l➥&7 Command Block editing"))
.lore(Text.color("&8&l➥&7 Command Block placing"))
.lore(Text.color("&8&l➥&7 Command Block using"))
.lore(Text.color("&8&l➥&7 Command Block Minecart placing"))
.lore(Text.color("&8&l➥&7 Command Block Minecart using"))
.lore(Text.color("&8&l➥&7 Creative Hotbar Items"))
.enchant(Enchantment.PROTECTION,64)
.flag(ItemFlag.HIDE_ENCHANTS)
.build();
public static ItemStack configItem(String valueName, Material material, String description) {
ServerUtils.verbose("Items#configItem: Creating a config item:\n Value Name -> %s\nMaterial in use -> %s".formatted(valueName,material.toString()));
List<String> desc = Arrays.stream(description.split("\n")).toList();
ItemBuilder item = ItemBuilder.create();
item.material(material);
item.name(Text.color("&6%s".formatted(valueName)));
for (String s : desc) {
item.lore(Text.color("&e%s".formatted(s)));
}
item.lore(Text.color("&8&l➥&7 Click to set a &nnew&r&7 value."));
item.lore(Text.color("&8&l➥&7 Current Value: &b_ORIGINAL_"));
return item.build();
}
public static ItemStack stringListItem(Iterable<String> values, Material material, String valueName, String description) {
ServerUtils.verbose("Items#stringListItem: Creating a config item:\n Value Name -> %s\nMaterial in use -> %s".formatted(valueName,material.toString()));
ItemBuilder itemBuilder = ItemBuilder.create();
itemBuilder.material(material);
itemBuilder.name(Text.color("&6%s".formatted(valueName)));
List<String> desc = Arrays.stream(description.split("\n")).toList();
for (String s : desc) {
itemBuilder.lore(Text.color("&e%s".formatted(s)));
}
itemBuilder.lore(Text.color("&8&l➥&7 Left-Click to add a new value."));
itemBuilder.lore(Text.color("&8&l➥&7 Right-Click to clear values."));
itemBuilder.lore(Text.color("&8&l➥&7 Current Values: "));
itemBuilder.flag(ItemFlag.HIDE_ATTRIBUTES);
for (String value : values) {
itemBuilder.lore(Text.color("&9 - &b%s".formatted(value)));
}
return itemBuilder.build();
}
public static ItemStack stringItem(String originalValue, ItemStack originalItem) {
ServerUtils.verbose("Items#stringItem Creating a string item:\n Value -> %s".formatted(originalValue));
if (originalItem == null || !originalItem.hasItemMeta()) return originalItem;
ItemMeta meta = originalItem.getItemMeta();
if (meta == null || !meta.hasLore()) return originalItem;
List<String> lore = meta.getLore();
if (lore == null) return originalItem;
for (int i = 0; i < lore.size(); i++) {
String line = lore.get(i);
ServerUtils.verbose("Items#stringItem Looping through lore line: %s/%s".formatted(i,lore.size()));
if (line.contains("_ORIGINAL_")) {
try {
ServerUtils.verbose("Items#stringItem Found a lore on line %s, making replacement value".formatted(i));
String replace = line.replace("_ORIGINAL_", originalValue);
ServerUtils.verbose("Items#stringItem After replacement -> %s".formatted(replace));
lore.set(i,replace);
ServerUtils.verbose("Items#stringItem Just replaced line %s -> %s".formatted(i,lore.get(i)));
} catch (Exception e) {
e.printStackTrace();
}
}
ServerUtils.verbose("Items#stringItem end of loop %s. continue?".formatted(i));
}
ServerUtils.verbose("Items#stringItem Broke out of loop, setting the lore");
meta.setLore(lore);
ServerUtils.verbose("Items#stringItem Setting the meta");
originalItem.setItemMeta(meta);
ServerUtils.verbose("Items#stringItem Returning the item");
return originalItem;
}
public static ItemStack booleanItem(boolean originalValue, ItemStack originalItem) {
ServerUtils.verbose("Items#booleanItem Creating a string item:\n Value -> %s".formatted(originalValue));
if (originalItem == null || !originalItem.hasItemMeta()) return originalItem;
ItemMeta meta = originalItem.getItemMeta();
if (meta == null || !meta.hasLore()) return originalItem;
List<String> lore = meta.getLore();
if (lore == null) return originalItem;
for (int i = 0; i < lore.size(); i++) {
String line = lore.get(i);
ServerUtils.verbose("Items#booleanItem Looping through lore line: %s/%s".formatted(i,lore.size()));
if (line.contains("_ORIGINAL_")) {
try {
ServerUtils.verbose("Items#booleanItem Found a lore on line %s, making replacement value".formatted(i));
String replace = line.replace("_ORIGINAL_", "" + originalValue);
ServerUtils.verbose("Items#booleanItem After replacement -> %s".formatted(replace));
lore.set(i,replace);
ServerUtils.verbose("Items#booleanItem Just replaced line %s -> %s".formatted(i,lore.get(i)));
} catch (Exception e) {
e.printStackTrace();
}
}
ServerUtils.verbose("Items#booleanItem end of loop %s. continue?".formatted(i));
}
ServerUtils.verbose("Items#booleanItem Broke out of loop, setting the lore");
meta.setLore(lore);
ServerUtils.verbose("Items#booleanItem Setting the meta");
originalItem.setItemMeta(meta);
ServerUtils.verbose("Items#booleanItem Returning the item");
return originalItem;
}
public static ItemStack intItem(int originalValue, ItemStack originalItem) {
ServerUtils.verbose("Items#intitem Creating a string item:\n Value -> %s".formatted(originalValue));
if (originalItem == null || !originalItem.hasItemMeta()) return originalItem;
ItemMeta meta = originalItem.getItemMeta();
if (meta == null || !meta.hasLore()) return originalItem;
List<String> lore = meta.getLore();
if (lore == null) return originalItem;
for (int i = 0; i < lore.size(); i++) {
String line = lore.get(i);
ServerUtils.verbose("Items#intitem Looping through lore line: %s/%s".formatted(i,lore.size()));
if (line.contains("_ORIGINAL_")) {
try {
ServerUtils.verbose("Items#intitem Found a lore on line %s, making replacement value".formatted(i));
String replace = line.replace("_ORIGINAL_", "" + originalValue);
ServerUtils.verbose("Items#intitem After replacement -> %s".formatted(replace));
lore.set(i,replace);
ServerUtils.verbose("Items#intitem Just replaced line %s -> %s".formatted(i,lore.get(i)));
} catch (Exception e) {
e.printStackTrace();
}
}
ServerUtils.verbose("Items#intitem end of loop %s. continue?".formatted(i));
}
ServerUtils.verbose("Items#intitem Broke out of loop, setting the lore");
meta.setLore(lore);
ServerUtils.verbose("Items#intitem Setting the meta");
originalItem.setItemMeta(meta);
ServerUtils.verbose("Items#intitem Returning the item");
return originalItem;
}
}

View File

@@ -0,0 +1,50 @@
package me.trouper.sentinel.server.gui;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class MainGUI {
public static Set<UUID> awaitingCallback = new HashSet<>();
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Home"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(12,Items.CREDITS)
.define(14,Items.CONFIG,this::openConfig)
.build();
private void openConfig(InventoryClickEvent e) {
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
verify((Player) e.getWhoClicked());
}
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
}
public static boolean verify(Player p) {
if (PlayerUtils.isTrusted(p)) return true;
Sentinel.log.info("WARNING: %s has just attempted to use the GUI without authorization. This has been prevented by Sentinel, as we are NOT Vulcan AntiCheat.");
p.closeInventory();
return false;
}
}

View File

@@ -0,0 +1,113 @@
package me.trouper.sentinel.server.gui.config;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.server.gui.ConfigGUI;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.*;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class AntiNukeGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Choose a check"))
.size(54)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(53, Items.BACK, e->{
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
})
.define(10,COMMAND_BLOCK_WHITELIST, e->{
e.getWhoClicked().openInventory(new CBExecuteGUI().home.getInventory());
})
.define(12,COMMAND_BLOCK_PLACE, e->{
e.getWhoClicked().openInventory(new CBPlaceGUI().home.getInventory());
})
.define(14,COMMAND_BLOCK_USE, e->{
e.getWhoClicked().openInventory(new CBUseGUI().home.getInventory());
})
.define(16,COMMAND_BLOCK_EDITING, e->{
e.getWhoClicked().openInventory(new CBEditGUI().home.getInventory());
})
.define(37,COMMAND_BLOCK_MINECART_USE, e->{
e.getWhoClicked().openInventory(new CBMCUseGUI().home.getInventory());
})
.define(39,COMMAND_BLOCK_MINECART_PLACE, e->{
e.getWhoClicked().openInventory(new CBMCPlaceGUI().home.getInventory());
})
.define(41,COMMAND_EXECUTE, e->{
e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
})
.define(43,HOTBAR_ACTION, e->{
e.getWhoClicked().openInventory(new HotbarActionGUI().home.getInventory());
})
.build();
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
MainGUI.verify((Player) e.getWhoClicked());
}
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
}
private static final ItemStack COMMAND_BLOCK_EDITING = ItemBuilder.create()
.material(Material.DEBUG_STICK)
.name(Text.color("&bCommand Block Editing"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack COMMAND_BLOCK_WHITELIST = ItemBuilder.create()
.material(Material.EMERALD)
.name(Text.color("&bCommand Block Whitelist"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack COMMAND_BLOCK_MINECART_PLACE = ItemBuilder.create()
.material(Material.RAIL)
.name(Text.color("&bCommand Block Minecart Placing"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack COMMAND_BLOCK_MINECART_USE = ItemBuilder.create()
.material(Material.COMMAND_BLOCK_MINECART)
.name(Text.color("&bCommand Block Minecart Using"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack COMMAND_BLOCK_PLACE = ItemBuilder.create()
.material(Material.CHAIN_COMMAND_BLOCK)
.name(Text.color("&bCommand Block Placing"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack COMMAND_BLOCK_USE = ItemBuilder.create()
.material(Material.REPEATING_COMMAND_BLOCK)
.name(Text.color("&bCommand Block Using"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack COMMAND_EXECUTE = ItemBuilder.create()
.material(Material.SPYGLASS)
.name(Text.color("&bCommand Execution"))
.lore(Text.color("&8&l➥&7 Dangerous Commands"))
.lore(Text.color("&8&l➥&7 Logged Commands"))
.lore(Text.color("&8&l➥&7 Specific Commands"))
.build();
private static final ItemStack HOTBAR_ACTION = ItemBuilder.create()
.material(Material.DIAMOND_SWORD)
.name(Text.color("&bNBT Items"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
}

View File

@@ -0,0 +1,72 @@
package me.trouper.sentinel.server.gui.config;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.server.gui.ConfigGUI;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.chat.ProfanityFilterGUI;
import me.trouper.sentinel.server.gui.config.chat.RegexFilterGUI;
import me.trouper.sentinel.server.gui.config.chat.SpamFilterGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class ChatGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Edit a Filter"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(11,REGEX_FILTERS,e->{
ServerUtils.verbose("ChatGUI#home Redirecting to RegexFilterGUI");
e.getWhoClicked().openInventory(new RegexFilterGUI().home.getInventory());
})
.define(13,PROFANITY_FILTER,e->{
e.getWhoClicked().openInventory(new ProfanityFilterGUI().home.getInventory());
})
.define(15,SPAM_FILTER,e->{
e.getWhoClicked().openInventory(new SpamFilterGUI().home.getInventory());
})
.define(26,Items.BACK,e->{
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
})
.build();
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
MainGUI.verify((Player) e.getWhoClicked());
}
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
}
private static final ItemStack PROFANITY_FILTER = ItemBuilder.create()
.material(Material.COAL)
.name(Text.color("&bProfanity Filter"))
.lore(Text.color("&8&l➥&7 Edit Score Settings"))
.build();
private static final ItemStack SPAM_FILTER = ItemBuilder.create()
.material(Material.PORKCHOP)
.name(Text.color("&bSpam Filter"))
.lore(Text.color("&8&l➥&7 Edit Heat Settings"))
.build();
private static final ItemStack REGEX_FILTERS = ItemBuilder.create()
.material(Material.DISPENSER)
.name(Text.color("&bRegex Filters"))
.lore(Text.color("&8&l➥&7 URL Blocker"))
.lore(Text.color("&8&l➥&7 Unicode Whitelist"))
.lore(Text.color("&8&l➥&7 Swear Regex"))
.lore(Text.color("&8&l➥&7 Spam Regex"))
.lore(Text.color("&8&l➥&7 False Positive Regex"))
.build();
}

View File

@@ -0,0 +1,133 @@
package me.trouper.sentinel.server.gui.config.chat;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.ChatGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
public class ProfanityFilterGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Editing Profanity Filter"))
.size(54)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(53, Items.BACK, e->{
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
try {
ServerUtils.verbose("ProfanityFilterGUI#blankPage Starting");
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ServerUtils.verbose("ProfanityFilterGUI#blankPage Page now blank");
ItemStack top = Items.RED;
if (Sentinel.mainConfig.chat.swearFilter.enabled) {
top = Items.GREEN;
}
for (int i = 0; i < 9; i++) {
inv.setItem(i,top);
}
ServerUtils.verbose("ProfanityFilterGUI#blankPage Adding GUI Items");
inv.setItem(53,Items.BACK);
inv.setItem(4,Items.booleanItem(Sentinel.mainConfig.chat.swearFilter.enabled, Items.configItem("Profanity Filter Toggle",Material.CLOCK,"Enable or Disable the whole Profanity filter")));
inv.setItem(10,Items.intItem(Sentinel.mainConfig.chat.swearFilter.lowScore, Items.configItem("Low Score Gain", Material.WHITE_WOOL, "How much score will be added if the player \ndid not attempt to bypass the filter.")));
inv.setItem(19,Items.intItem(Sentinel.mainConfig.chat.swearFilter.mediumLowScore, Items.configItem("Medium-Low Score Gain", Material.LIME_WOOL, "How much score will be added if the player \nused l33t speak to attempt a bypass")));
inv.setItem(28,Items.intItem(Sentinel.mainConfig.chat.swearFilter.mediumScore, Items.configItem("Medium Score Gain", Material.YELLOW_WOOL, "How much score will be added if the player \nused sp/ecia|l characters to attempt a bypass")));
inv.setItem(37,Items.intItem(Sentinel.mainConfig.chat.swearFilter.mediumHighScore, Items.configItem("Medium-High Score Gain", Material.ORANGE_WOOL, "How much score will be added if the player \nused reeeeeeepeating letters to attempt a bypass")));
inv.setItem(46,Items.intItem(Sentinel.mainConfig.chat.swearFilter.highScore, Items.configItem("High Score Gain", Material.RED_WOOL, "How much score will be added if the player \nused pun. ctua, tion or spaces to attempt a bypass")));
inv.setItem(29,Items.intItem(Sentinel.mainConfig.chat.swearFilter.regexScore, Items.configItem("Regex Score Gain", Material.DISPENSER, "How much score will be added if the player \nmatched the regex setting throughout \nthe processing of the message")));
inv.setItem(22,Items.intItem(Sentinel.mainConfig.chat.swearFilter.punishScore, Items.configItem("Punish Score", Material.IRON_BARS, "If the player's score is above this \nthe punishment commands will be ran.")));
inv.setItem(33,Items.intItem(Sentinel.mainConfig.chat.swearFilter.scoreDecay, Items.configItem("Score Decay", Material.DEAD_BUBBLE_CORAL_BLOCK, "How much score players will loose each minute.")));
inv.setItem(31,Items.stringListItem(Sentinel.mainConfig.chat.swearFilter.swearPunishCommands,Material.WOODEN_AXE, "Default Punishment Commands", "%player% will be replaced with the offender's name"));
inv.setItem(40,Items.stringListItem(Sentinel.mainConfig.chat.swearFilter.strictPunishCommands,Material.DIAMOND_AXE, "Strict Punishment Commands", "If words from the strict words list are flagged, \nthis list will be ran instead \n%player% will be replaced with the offender's name"));
} catch (Exception e) {
e.printStackTrace();
}
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 4 -> {
Sentinel.mainConfig.chat.swearFilter.enabled = !Sentinel.mainConfig.chat.swearFilter.enabled;
blankPage(e.getInventory());
Sentinel.mainConfig.save();
}
case 10 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.lowScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.lowScore);
case 19 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.mediumLowScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.mediumLowScore);
case 28 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.mediumScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.mediumScore);
case 37 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.mediumHighScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.mediumHighScore);
case 46 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.highScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.highScore);
case 29 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.regexScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.regexScore);
case 22 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.punishScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.punishScore);
case 33 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.swearFilter.scoreDecay = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.swearFilter.scoreDecay);
case 31 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.swearFilter.swearPunishCommands.add(args.getAll().toString());
},"" + Sentinel.mainConfig.chat.swearFilter.swearPunishCommands);
return;
}
Sentinel.mainConfig.chat.swearFilter.swearPunishCommands.clear();
blankPage(e.getInventory());
Sentinel.mainConfig.save();
}
case 40 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.swearFilter.strictPunishCommands.add(args.getAll().toString());
},"" + Sentinel.mainConfig.chat.swearFilter.strictPunishCommands);
return;
}
Sentinel.mainConfig.chat.swearFilter.strictPunishCommands.clear();
blankPage(e.getInventory());
Sentinel.mainConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, MainConfig> updater = new ConfigUpdater<>(Sentinel.mainConfig);
private void queuePlayer(Player player, BiConsumer<MainConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,89 @@
package me.trouper.sentinel.server.gui.config.chat;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.events.CustomListener;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.AdvancedConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.ChatGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import java.util.function.BiConsumer;
public class RegexFilterGUI implements CustomListener {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Edit a Chat Filter"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
inv.setItem(26,Items.BACK);
ServerUtils.verbose("RegexFilterGUI#blankPage Setting up page");
inv.setItem(11, Items.stringItem(Sentinel.advConfig.allowedCharRegex, Items.configItem("Unicode Whitelist", Material.FEATHER, "The regex defining what characters \nare allowed to be used in chat.")));
ServerUtils.verbose("RegexFilterGUI#blankPage Finished with Unicode Whitelist");
inv.setItem(12, Items.stringItem(Sentinel.advConfig.falsePosRegex, Items.configItem("False Positive Regex", Material.EMERALD, "This regex will be replaced with \nan empty string before profanity filter \nprocessing begins.")));
ServerUtils.verbose("RegexFilterGUI#blankPage Finished with False Positive Regex");
inv.setItem(13, Items.stringItem(Sentinel.advConfig.swearRegex, Items.configItem("Swear Regex", Material.ROTTEN_FLESH, "If anything matches to this regex, \nthe profanity filter will immediately flag it.")));
ServerUtils.verbose("RegexFilterGUI#blankPage Finished with Swear Regex");
inv.setItem(14, Items.stringItem(Sentinel.advConfig.strictRegex, Items.configItem("Strict Regex", Material.LEAD, "If anything matches to this regex, the profanity \nfilter will immediately flag it as a slur.")));
ServerUtils.verbose("RegexFilterGUI#blankPage Finished with Strict Regex");
inv.setItem(15, Items.stringItem(Sentinel.advConfig.urlRegex, Items.configItem("URL Blocker", Material.CHAIN, "If anything matches to this regex, it will get \nflagged as a URL.")));
ServerUtils.verbose("RegexFilterGUI#blankPage Done Setting up page (Finished URL Blocker)");
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
SchedulerUtils.later(0,()->{
switch (e.getSlot()) {
case 11 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.allowedCharRegex = args.getAll().toString(),Sentinel.advConfig.allowedCharRegex);
case 12 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.falsePosRegex = args.getAll().toString(),Sentinel.advConfig.falsePosRegex);
case 13 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.swearRegex = args.getAll().toString(),Sentinel.advConfig.swearRegex);
case 14 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.strictRegex = args.getAll().toString(),Sentinel.advConfig.strictRegex);
case 15 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.urlRegex = args.getAll().toString(),Sentinel.advConfig.urlRegex);
}
});
}
public static ConfigUpdater<AsyncPlayerChatEvent, AdvancedConfig> updater = new ConfigUpdater<>(Sentinel.advConfig);
private void queuePlayer(Player player, BiConsumer<AdvancedConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,117 @@
package me.trouper.sentinel.server.gui.config.chat;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.ChatGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
public class SpamFilterGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Editing Spam Filter"))
.size(54)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(53, Items.BACK, e->{
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack top = Items.RED;
if (Sentinel.mainConfig.chat.spamFilter.enabled) {
top = Items.GREEN;
}
for (int i = 0; i < 9; i++) {
inv.setItem(i,top);
}
inv.setItem(53,Items.BACK);
inv.setItem(4,Items.booleanItem(Sentinel.mainConfig.chat.spamFilter.enabled, Items.configItem("Spam Filter Toggle", Material.CLOCK, "Enable or disable the whole Spam Filter")));
inv.setItem(10,Items.intItem(Sentinel.mainConfig.chat.spamFilter.defaultGain, Items.configItem("Default Heat Gain", Material.BUCKET, "How much heat will be added to each message.")));
inv.setItem(19,Items.intItem(Sentinel.mainConfig.chat.spamFilter.lowGain, Items.configItem("Low Heat Gain", Material.WATER_BUCKET, "Extra heat to be added if the \nmessage is greater than 25% similar \nto their previous message.")));
inv.setItem(28,Items.intItem(Sentinel.mainConfig.chat.spamFilter.mediumGain, Items.configItem("Medium Heat Gain", Material.COD_BUCKET, "Extra heat to be added if the \nmessage is greater than 50% similar \nto their previous message.")));
inv.setItem(37,Items.intItem(Sentinel.mainConfig.chat.spamFilter.highGain, Items.configItem("High Heat Gain", Material.PUFFERFISH_BUCKET, "Extra heat to be added if the \nmessage is greater than 90% similar \nto their previous message.")));
inv.setItem(46,Items.intItem(Sentinel.mainConfig.chat.spamFilter.blockHeat, Items.configItem("Block Heat", Material.BARRIER, "If the player's heat is above this \nthen their message will be blocked and \nflagged as spam.")));
inv.setItem(21,Items.intItem(Sentinel.mainConfig.chat.spamFilter.blockSimilarity, Items.configItem("Block Similarity", Material.BARRIER, "If the message's similarity is above \nthis, it will get automatically blocked \nand flagged as spam.")));
inv.setItem(23,Items.intItem(Sentinel.mainConfig.chat.spamFilter.punishHeat, Items.configItem("Punish Heat", Material.IRON_BARS, "If the player's heat is above this \nthe punishment commands will be ran.")));
inv.setItem(25,Items.intItem(Sentinel.mainConfig.chat.spamFilter.heatDecay, Items.configItem("Heat Decay", Material.DEAD_BUBBLE_CORAL_BLOCK, "How much heat players will loose each second.")));
inv.setItem(32,Items.stringListItem(Sentinel.mainConfig.chat.spamFilter.punishCommands,Material.DIAMOND_AXE, "Punishment Commands", "%player% will be replaced with the offender's name"));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
blankPage(e.getInventory());
switch (e.getSlot()) {
case 4 -> {
Sentinel.mainConfig.chat.spamFilter.enabled = !Sentinel.mainConfig.chat.spamFilter.enabled;
blankPage(e.getInventory());
Sentinel.mainConfig.save();
}
case 10 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.defaultGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.defaultGain);
case 19 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.lowGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.lowGain);
case 28 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.mediumGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.mediumGain);
case 37 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.highGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.highGain);
case 46 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.blockHeat = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.blockHeat);
case 21 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.blockSimilarity = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.blockSimilarity);
case 23 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.punishHeat = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.punishHeat);
case 25 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.heatDecay = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.heatDecay);
case 32 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.spamFilter.punishCommands.add(args.getAll().toString());
},"" + Sentinel.mainConfig.chat.spamFilter.punishCommands);
return;
}
Sentinel.mainConfig.chat.spamFilter.punishCommands.clear();
blankPage(e.getInventory());
Sentinel.mainConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, MainConfig> updater = new ConfigUpdater<>(Sentinel.mainConfig);
private void queuePlayer(Player player, BiConsumer<MainConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,67 @@
package me.trouper.sentinel.server.gui.config.nuke;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.command.DangerousCMDGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.command.LoggedCMDGUI;
import me.trouper.sentinel.server.gui.config.nuke.checks.command.SpecificCMDGUI;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class CommandGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Choose a check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.define(11,SPECIFIC, e->{
e.getWhoClicked().openInventory(new SpecificCMDGUI().home.getInventory());
})
.define(13,LOGGED, e->{
e.getWhoClicked().openInventory(new LoggedCMDGUI().home.getInventory());
})
.define(15,DANGEROUS, e->{
e.getWhoClicked().openInventory(new DangerousCMDGUI().home.getInventory());
})
.build();
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
MainGUI.verify((Player) e.getWhoClicked());
}
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
}
private static final ItemStack SPECIFIC = ItemBuilder.create()
.material(Material.SPECTRAL_ARROW)
.name(Text.color("&bSpecific Commands"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack LOGGED = ItemBuilder.create()
.material(Material.SPYGLASS)
.name(Text.color("&bLogged Commands"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
private static final ItemStack DANGEROUS = ItemBuilder.create()
.material(Material.TNT)
.name(Text.color("&bDangerous Commands"))
.lore(Text.color("&8&l➥&7 Modify this check"))
.build();
}

View File

@@ -0,0 +1,118 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class CBEditGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 CB Edit Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandBlockEdit.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockEdit.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandBlockEdit.enabled = !Sentinel.violationConfig.commandBlockEdit.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.commandBlockEdit.deop = !Sentinel.violationConfig.commandBlockEdit.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.commandBlockEdit.logToDiscord = !Sentinel.violationConfig.commandBlockEdit.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.commandBlockEdit.punish = !Sentinel.violationConfig.commandBlockEdit.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.commandBlockEdit.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandBlockEdit.punishmentCommands);
return;
}
Sentinel.violationConfig.commandBlockEdit.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,74 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class CBExecuteGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 CB Whitelist"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack top = Items.RED;
if (Sentinel.violationConfig.commandBlockExecute.enabled) {
top = Items.GREEN;
}
for (int i = 0; i < 9; i++) {
inv.setItem(i,top);
}
inv.setItem(26,Items.BACK);
inv.setItem(4,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(11,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.destroyBlock,Items.configItem("Destroy",Material.NETHERITE_PICKAXE,"Destroy the offending command-block")));
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.attemptRestore,Items.configItem("Restore",Material.COMMAND_BLOCK,"Attempt to restore the block if a \nwhitelisted one exists at the location")));
inv.setItem(15,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 4 -> {
Sentinel.violationConfig.commandBlockExecute.enabled = !Sentinel.violationConfig.commandBlockExecute.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 11 -> {
Sentinel.violationConfig.commandBlockExecute.destroyBlock = !Sentinel.violationConfig.commandBlockExecute.destroyBlock;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 13 -> {
Sentinel.violationConfig.commandBlockExecute.attemptRestore = !Sentinel.violationConfig.commandBlockExecute.attemptRestore;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 15 -> {
Sentinel.violationConfig.commandBlockExecute.logToDiscord = !Sentinel.violationConfig.commandBlockExecute.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
}

View File

@@ -0,0 +1,118 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class CBMCPlaceGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 CB MC Place Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandBlockMinecartPlace.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandBlockMinecartPlace.enabled = !Sentinel.violationConfig.commandBlockMinecartPlace.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.commandBlockMinecartPlace.deop = !Sentinel.violationConfig.commandBlockMinecartPlace.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord = !Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.commandBlockMinecartPlace.punish = !Sentinel.violationConfig.commandBlockMinecartPlace.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.commandBlockMinecartPlace.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands);
return;
}
Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,119 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class CBMCUseGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 CB MC Use Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandBlockMinecartUse.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandBlockMinecartUse.enabled = !Sentinel.violationConfig.commandBlockMinecartUse.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.commandBlockMinecartUse.deop = !Sentinel.violationConfig.commandBlockMinecartUse.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord = !Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.commandBlockMinecartUse.punish = !Sentinel.violationConfig.commandBlockMinecartUse.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.commandBlockMinecartUse.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands);
return;
}
Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60,(e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,119 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class CBPlaceGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 CB Place Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandBlockPlace.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandBlockPlace.enabled = !Sentinel.violationConfig.commandBlockPlace.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.commandBlockPlace.deop = !Sentinel.violationConfig.commandBlockPlace.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.commandBlockPlace.logToDiscord = !Sentinel.violationConfig.commandBlockPlace.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.commandBlockPlace.punish = !Sentinel.violationConfig.commandBlockPlace.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.commandBlockPlace.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandBlockPlace.punishmentCommands);
return;
}
Sentinel.violationConfig.commandBlockPlace.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,119 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class CBUseGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 CB Use Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandBlockUse.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandBlockUse.enabled = !Sentinel.violationConfig.commandBlockUse.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.commandBlockUse.deop = !Sentinel.violationConfig.commandBlockUse.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.commandBlockUse.logToDiscord = !Sentinel.violationConfig.commandBlockUse.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.commandBlockUse.punish = !Sentinel.violationConfig.commandBlockUse.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.commandBlockUse.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandBlockUse.punishmentCommands);
return;
}
Sentinel.violationConfig.commandBlockUse.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,120 @@
package me.trouper.sentinel.server.gui.config.nuke.checks;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class HotbarActionGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Creative Hotbar Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this:: mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.creativeHotbarAction.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.creativeHotbarAction.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.creativeHotbarAction.enabled = !Sentinel.violationConfig.creativeHotbarAction.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.creativeHotbarAction.deop = !Sentinel.violationConfig.creativeHotbarAction.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.creativeHotbarAction.logToDiscord = !Sentinel.violationConfig.creativeHotbarAction.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.creativeHotbarAction.punish = !Sentinel.violationConfig.creativeHotbarAction.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.creativeHotbarAction.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.creativeHotbarAction.punishmentCommands);
return;
}
Sentinel.violationConfig.creativeHotbarAction.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,131 @@
package me.trouper.sentinel.server.gui.config.nuke.checks.command;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class DangerousCMDGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Dangerous Command Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandExecute.dangerous.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
inv.setItem(22,Items.stringListItem(Sentinel.violationConfig.commandExecute.dangerous.commands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands that will flag this check."));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandExecute.dangerous.enabled = !Sentinel.violationConfig.commandExecute.dangerous.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 2 -> {
Sentinel.violationConfig.commandExecute.dangerous.deop = !Sentinel.violationConfig.commandExecute.dangerous.deop;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 20 -> {
Sentinel.violationConfig.commandExecute.dangerous.logToDiscord = !Sentinel.violationConfig.commandExecute.dangerous.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 6 -> {
Sentinel.violationConfig.commandExecute.dangerous.punish = !Sentinel.violationConfig.commandExecute.dangerous.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.commandExecute.dangerous.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands);
return;
}
Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 22 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.commandExecute.dangerous.commands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandExecute.dangerous.commands);
return;
}
Sentinel.violationConfig.commandExecute.dangerous.commands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,103 @@
package me.trouper.sentinel.server.gui.config.nuke.checks.command;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.function.BiConsumer;
public class LoggedCMDGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Logged Command Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack ring = Items.RED;
if (Sentinel.violationConfig.commandExecute.logged.enabled) {
ring = Items.GREEN;
}
List<Integer> ringList = List.of(3,4,5,12,14,21,22,23);
for (Integer i : ringList) {
inv.setItem(i,ring);
}
inv.setItem(26,Items.BACK);
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandExecute.logged.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(11,Items.booleanItem(Sentinel.violationConfig.commandExecute.logged.logToDiscord,Items.configItem("Log to Discord",Material.OAK_LOG,"If this check will log to discord")));
inv.setItem(15,Items.stringListItem(Sentinel.violationConfig.commandExecute.logged.commands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands that will flag this check"));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 13 -> {
Sentinel.violationConfig.commandExecute.logged.enabled = !Sentinel.violationConfig.commandExecute.logged.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 11 -> {
Sentinel.violationConfig.commandExecute.logged.logToDiscord = !Sentinel.violationConfig.commandExecute.logged.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 15 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.commandExecute.logged.commands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandExecute.logged.commands);
return;
}
Sentinel.violationConfig.commandExecute.logged.commands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,108 @@
package me.trouper.sentinel.server.gui.config.nuke.checks.command;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.ViolationConfig;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
public class SpecificCMDGUI {
public final CustomGui home = CustomGui.create()
.title(Text.color("&6&lSentinel &8»&0 Specific Command Check"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26, Items.BACK, e->{
e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
})
.build();
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack top = Items.RED;
if (Sentinel.violationConfig.commandExecute.specific.enabled) {
top = Items.GREEN;
}
for (int i = 0; i < 9; i++) {
inv.setItem(i,top);
}
inv.setItem(26,Items.BACK);
inv.setItem(4,Items.booleanItem(Sentinel.violationConfig.commandExecute.specific.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
inv.setItem(11,Items.booleanItem(Sentinel.violationConfig.commandExecute.specific.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"If this check will run the punishment commands")));
inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandExecute.specific.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
inv.setItem(15,Items.stringListItem(Sentinel.violationConfig.commandExecute.specific.punishmentCommands,Material.DIAMOND_AXE,"Commands","Commands that will flag this check"));
}
private void mainClick(InventoryClickEvent e) {
e.setCancelled(true);
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 4 -> {
Sentinel.violationConfig.commandExecute.specific.enabled = !Sentinel.violationConfig.commandExecute.specific.enabled;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 13 -> {
Sentinel.violationConfig.commandExecute.specific.logToDiscord = !Sentinel.violationConfig.commandExecute.specific.logToDiscord;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 11 -> {
Sentinel.violationConfig.commandExecute.specific.punish = !Sentinel.violationConfig.commandExecute.specific.punish;
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
case 15 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
cfg.commandExecute.specific.punishmentCommands.add(args.getAll().toString());
},"" + Sentinel.violationConfig.commandExecute.specific.punishmentCommands);
return;
}
Sentinel.violationConfig.commandExecute.specific.punishmentCommands.clear();
blankPage(e.getInventory());
Sentinel.violationConfig.save();
}
}
}
public static ConfigUpdater<AsyncPlayerChatEvent, ViolationConfig> updater = new ConfigUpdater<>(Sentinel.violationConfig);
private void queuePlayer(Player player, BiConsumer<ViolationConfig, Args> action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
player.closeInventory();
updater.queuePlayer(player, 20*60, (e)->{
e.setCancelled(true);
ServerUtils.verbose("Supplying the message: \"%s\". Canceled? %s".formatted(e.getMessage(),e.isCancelled()));
return e.getMessage();
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
player.sendMessage(Text.prefix("Value updated successfully"));
player.openInventory(home.getInventory());
});
player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
}
}

View File

@@ -0,0 +1,81 @@
package me.trouper.sentinel.startup;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.CipherUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class AntiPiracy {
public static boolean sailTheSevenSeas() {
Sentinel.log.info("Docking Vesel");
File sentinel = Sentinel.us;
Sentinel.log.info("Obtaining Gold");
String hash = CipherUtils.getFileHash(sentinel);
Sentinel.log.info("Checking for fake coin");
if (hash == null) {
Sentinel.log.info("Counterfeiter!");
return true;
}
Set<String> allowedHashes = getHashList();
if (allowedHashes == null || allowedHashes.isEmpty()) {
Sentinel.log.info("No Booty?");
return true;
}
if (allowedHashes.contains(hash)) {
Sentinel.log.info("Checkpoint 1 Complete");
return false;
} else {
Sentinel.log.info("Well,");
return true;
}
}
public static Set<String> getHashList() {
Sentinel.log.info("Initializing East India Protocol");
try {
String urlString = "http://api.trouper.me:8080/sentinel-hashes";
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
Sentinel.log.info("Bargaining with merchants");
int responseCode = conn.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new IOException("Failed to get response from server, response code: " + responseCode);
}
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
conn.disconnect();
Sentinel.log.info("Counting Coins");
Gson gson = new Gson();
return gson.fromJson(content.toString(), new TypeToken<Set<String>>() {}.getType());
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,153 @@
package me.trouper.sentinel.startup;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.AdvancedConfig;
import me.trouper.sentinel.utils.MathUtils;
import org.bukkit.Bukkit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Auth {
public static String serverID = "NULL";
public static String licenseKey = "NULL";
public static String nonce = "NULL";
public static String ip = "NULL";
public static int port = 0;
public static boolean canLoad() {
switch (authorize()) {
case "AUTHORIZED" -> {
return true;
}
case "MINEHUT" -> {
boolean minehutStatus = Telemetry.initTelemetryHook() && Telemetry.report("Dynamic IP server has initialized.","Successful \"Auth\".");
if (minehutStatus) {
Sentinel.log.info("Dynamic IP auth Success!");
return true;
} else {
Sentinel. log.info("Dynamic IP Failure. Webhook Error possible? Please contact obvWolf to fix this.");
return false;
}
}
}
return false;
}
public static String authorize() {
Map<String, List<String>> licenses = getLicenseList();
if (licenses == null) return "ERROR";
if (licenses.containsKey(getLicenseKey())) {
List<String> allowedIDs = licenses.get(getLicenseKey());
if (allowedIDs.contains(serverID)) {
return "AUTHORIZED";
} else if (allowedIDs.contains("minehut")) {
return "MINEHUT";
} else {
return "INVALID-ID";
}
}
return "UNREGISTERED";
}
public static String getServerID() {
if (serverID == null || "NULL".equalsIgnoreCase(serverID)) {
try {
serverID = MathUtils.SHA256(getPublicIPAddress() + getPort());
return serverID;
} catch (Exception e) {
return MathUtils.SHA256(getNonce() + getPort());
}
}
return serverID;
}
public static Map<String, List<String>> getLicenseList() {
try {
String urlString = "http://api.trouper.me:8080/sentinel";
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
int responseCode = conn.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new IOException("Failed to get response from server, response code: " + responseCode);
}
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
conn.disconnect();
Gson gson = new Gson();
return gson.fromJson(content.toString(), new TypeToken<HashMap<String, List<String>>>() {}.getType());
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public static String getPublicIPAddress() throws IOException {
String apiUrl = "http://checkip.amazonaws.com";
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
ip = response.toString().trim();
return ip;
} else {
throw new IOException("Failed to get public IP address. HTTP error code: " + responseCode);
}
} finally {
connection.disconnect();
}
}
public static int getPort() {
port = Bukkit.getPort();
return port;
}
public static String getNonce() {
if (nonce == null || nonce.equals("NULL")) nonce = MathUtils.MD5(AdvancedConfig.nonce);
return nonce;
}
public static String getLicenseKey() {
licenseKey = Sentinel.mainConfig.plugin.license;
return licenseKey;
}
}

View File

@@ -0,0 +1,135 @@
package me.trouper.sentinel.startup;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.profanity.AntiProfanity;
import me.trouper.sentinel.server.functions.chatfilter.spam.AntiSpam;
import me.trouper.sentinel.server.commands.*;
import me.trouper.sentinel.server.events.*;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Bukkit;
public class Load {
public static boolean lite = false;
public static void load(String license, String serverID) {
/*if (AntiPiracy.sailTheSevenSeas()) {
Sentinel.log.info("That's Aught to be the worst pirate I've ever seen...");
Sentinel.log.warning("Your Sentinel distribution is illegal. Its DistroID is %s. It is not valid in the online registry.".formatted(CipherUtils.getFileHash(Sentinel.us)));
liteStart("Failed Distribution Check (Modified Jar?)");
return;
}*/
try {
Sentinel.log.info("Auth Requested...");
switch (Auth.authorize()) {
case "AUTHORIZED" -> {
Sentinel.log.info("\n]======----- Auth Success! -----======[");
startup(true);
}
case "MINEHUT" -> {
boolean minehutStatus = Telemetry.initTelemetryHook() && Telemetry.report("Dynamic IP server has initialized.","Successful \"Auth\".");
if (minehutStatus) {
Sentinel.log.info("Dynamic IP auth Success!");
startup(true);
} else {
Sentinel. log.info("Dynamic IP Failure. Webhook Error possible? Please contact obvWolf to fix this.");
liteStart("How is this even possible?");
}
}
case "INVALID-ID" -> {
Sentinel.log.info("Authentication Failure, You have not whitelisted this server ID yet.");
liteStart("They have not whitelisted their server ID yet. (License exists, no ID)");
}
case "UNREGISTERED" -> {
Sentinel.log.warning("Authentication Failure, YOU SHALL NOT PASS! License: %s Server ID: %s".formatted(license,serverID));
liteStart("They do not have a license key");
}
case "ERROR" -> {
Sentinel.log.warning("Hmmmmmm thats not right... License: %s Server ID: %s\nPlease report the above stacktrace.".formatted(license,serverID));
liteStart("An expected error occurred which prevented them from launching");
}
default -> {
Sentinel.log.warning("Achievement unlocked: How did we get here? License: %s Server ID: %s\nPlease report the above stacktrace.".formatted(license,serverID));
liteStart("An unexpected error occured which prevented them from launching");
}
}
} catch (Exception e) {
e.printStackTrace();
Sentinel.log.info("WTFFFF ARE YOU DOING MAN??????");
liteStart("An exception was thrown, then caught.");
}
}
public static void liteStart(String reason) {
lite = true;
Telemetry.initTelemetryHook();
Telemetry.report("Server has launched in lite mode",reason);
new SentinelCommand().register();
Sentinel.log.info("""
Finished!
____ __ ___ \s
/\\ _`\\ /\\ \\__ __ /\\_ \\ \s
\\ \\,\\L\\_\\ __ ___\\ \\ ,_\\/\\_\\ ___ __\\//\\ \\ \s
\\/_\\__ \\ /'__`\\/' _ `\\ \\ \\/\\/\\ \\ /' _ `\\ /'__`\\\\ \\ \\ \s
/\\ \\L\\ \\/\\ __//\\ \\/\\ \\ \\ \\_\\ \\ \\/\\ \\/\\ \\/\\ __/ \\_\\ \\_\s
\\ `\\____\\ \\____\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\_\\ \\_\\ \\____\\/\\____\\
\\/_____/\\/____/\\/_/\\/_/\\/__/ \\/_/\\/_/\\/_/\\/____/\\/____/
]==-- Enabled Lite mode. Go verify your purchase. --==[
""");
SchedulerUtils.repeat(20*30,()->{
if (lite) {
Sentinel.log.info(Text.removeColors(SentinelCommand.liteMode));
}
});
}
public static void startup(boolean coldStart) {
Sentinel.log.info("\n]======----- Loading Sentinel! -----======[");
lite = false;
// Plugin startup logic
Sentinel.log.info("Starting Up! (%s)...".formatted(Sentinel.getInstance().getDescription().getVersion()));
// Commands
if (coldStart) new SentinelCommand().register();
new MessageCommand().register();
new ReplyCommand().register();
new ReopCommand().register();
new CallbackCommand().register();
// Events
new CBEditEvent().register();
new CBExecuteEvent().register();
new CBMCPlaceEvent().register();
new CBMCUseEvent().register();
new CBPlaceEvent().register();
new CBUseEvent().register();
new ChatEvent().register();
new CommandExecuteEvent().register();
new CreativeHotbarEvent().register();
new TrapCommand().register();
new PluginCloakingEvents().register();
if (Sentinel.doNoPlugins) {
PluginCloakingEvents.registerEvent(Sentinel.getInstance());
}
// Scheduled timers
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), AntiSpam::decayHeat,0, 20);
Bukkit.getScheduler().runTaskTimer(Sentinel.getInstance(), AntiProfanity::decayScore,0,1200);
Sentinel.log.info("""
Finished!
____ __ ___ \s
/\\ _`\\ /\\ \\__ __ /\\_ \\ \s
\\ \\,\\L\\_\\ __ ___\\ \\ ,_\\/\\_\\ ___ __\\//\\ \\ \s
\\/_\\__ \\ /'__`\\/' _ `\\ \\ \\/\\/\\ \\ /' _ `\\ /'__`\\\\ \\ \\ \s
/\\ \\L\\ \\/\\ __//\\ \\/\\ \\ \\ \\_\\ \\ \\/\\ \\/\\ \\/\\ __/ \\_\\ \\_\s
\\ `\\____\\ \\____\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\_\\ \\_\\ \\____\\/\\____\\
\\/_____/\\/____/\\/_/\\/_/\\/__/ \\/_/\\/_/\\/_/\\/____/\\/____/
]====---- Advanced Anti-Grief & Chat Filter ----====[""");
}
}

View File

@@ -0,0 +1,124 @@
package me.trouper.sentinel.startup;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.CipherUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Telemetry {
public static String webhook;
public static boolean initTelemetryHook() {
webhook = fetchTelemetryHook();
return !webhook.equals("NULL");
}
public static boolean report(String title, String reason) {
int port = Auth.getPort();
DiscordEmbed embed = new DiscordEmbed.Builder()
.color(0xFF0000)
.author("Sentinel Startup Log")
.title(title)
.desc("""
**__License Info__**
License: `%s`
Nonce: `%s`
File Hash: `%s`
Purchaser: `%s` | `%s`
**__Server Info__**
ID: `%s`
Address: `%s`
Port: `%s`
**__Extra Info__**
%s
""".formatted(
Auth.getLicenseKey(),
Auth.getNonce(),
CipherUtils.getFileHash(Sentinel.us),
MainConfig.username,
MainConfig.user,
Auth.getServerID(),
Auth.ip,
port,
reason
)).build();
try {
EmbedFormatter.sendEmbed(embed,webhook);
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}
public static String fetchTelemetryHook() {
if (webhook == null || "NULL".equals(webhook)) {
try {
final String webhook = extractWebhook(fetchHtmlContent("https://trouper.me/auth/telemetry"));
// ServerUtils.verbose("Original Webhook: " + webhook);
String webhookIdPart = webhook.replaceAll(".*/(\\d+)/([^/]+.*)$", "/$1/");
// ServerUtils.verbose("Webhook ID Part: " + webhookIdPart);
String encrypted = webhook.replaceAll(".*/\\d+/([^/]+.*)$", "$1");
// ServerUtils.verbose("Encrypted Part: " + encrypted);
String isolated = webhook.replaceAll("/\\d+/([^/]+.*)$", "");
//ServerUtils.verbose("Isolated Part: " + isolated);
String decrypted = isolated + webhookIdPart + CipherUtils.decrypt(encrypted);
//ServerUtils.verbose("Decrypted Result: " + decrypted);
return decrypted;
} catch (Exception ex) {
Sentinel.log.warning("FAILED TO LOAD TELEMETRY (Are the servers up?)");
ex.printStackTrace();
return "NULL";
}
}
return webhook;
}
private static String fetchHtmlContent(String urlString) throws Exception {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
connection.disconnect();
return response.toString();
}
private static String extractWebhook(String htmlContent) {
String pattern = "data-hook=\"(.*?)\"";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(htmlContent);
if (m.find()) {
return m.group(1);
} else {
return "Webhook ID not found";
}
}
}

View File

@@ -0,0 +1,75 @@
package me.trouper.sentinel.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class CipherUtils {
private static final String secretKey = "GG8T885O4Yd/86OMVFdL0w=="; // 16, 24, or 32 bytes
private static final String algorithm = "AES";
public static String encrypt(String strToEncrypt) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(strToEncrypt.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String decrypt(String strToDecrypt) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(strToDecrypt));
return new String(decryptedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String getFileHash(File file) {
try {
// Create a MessageDigest instance for SHA-256
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// Read the file's content
FileInputStream fis = new FileInputStream(file);
byte[] byteArray = new byte[1024];
int bytesRead;
// Update the MessageDigest with the file's data
while ((bytesRead = fis.read(byteArray)) != -1) {
digest.update(byteArray, 0, bytesRead);
}
fis.close();
// Get the hash's bytes
byte[] hashBytes = digest.digest();
// Convert the hash's bytes to a hex string
StringBuilder hexString = new StringBuilder();
for (byte b : hashBytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,104 @@
package me.trouper.sentinel.utils;
import io.github.itzispyder.pdk.utils.FileValidationUtils;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.Randomizer;
import org.bukkit.inventory.ItemStack;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class FileUtils {
public static boolean folderExists(String folderName) {
File folder = new File(Sentinel.dataFolder(), folderName);
return folder.exists() && folder.isDirectory();
}
public static void createFolder(String folderName) {
File folder = new File(Sentinel.dataFolder(), folderName);
if (!folder.exists()) {
folder.mkdirs();
}
}
public static String createNBTLog(String contents) {
ServerUtils.verbose("FileUtils: Creating NBT log");
String fileName = "nbt_log-" + Randomizer.generateID();
File dataFolder = Sentinel.dataFolder();
File loggedNBTFolder = new File(dataFolder,"LoggedNBT");
if (!loggedNBTFolder.exists()) {
loggedNBTFolder.mkdirs();
}
File file = new File(loggedNBTFolder, fileName + ".txt");
try {
if (!file.exists()) {
file.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));
writer.append(contents);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return fileName;
}
public static String createNBTLog(ItemStack i) {
ServerUtils.verbose("FileUtils: Creating NBT log");
String item = i.getType().name().toLowerCase() + i.getItemMeta().getAsString();
String fileName = "nbt_log-" + Randomizer.generateID();
File dataFolder = Sentinel.dataFolder();
File loggedNBTFolder = new File(dataFolder,"LoggedNBT");
if (!loggedNBTFolder.exists()) {
loggedNBTFolder.mkdirs();
}
File file = new File(loggedNBTFolder, fileName + ".txt");
try {
if (!file.exists()) {
file.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));
writer.append(item);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return fileName;
}
public static String createCommandLog(String command) {
String fileName = "command_log-" + Randomizer.generateID();
File file = new File(Sentinel.dataFolder() + "/LoggedCommands/" + fileName + ".txt");
FileValidationUtils.validate(file);
try {
if (!file.exists()) {
file.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));
writer.append(command);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return fileName;
}
}

View File

@@ -0,0 +1,306 @@
package me.trouper.sentinel.utils;
import me.trouper.sentinel.Sentinel;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.Container;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Map;
import static org.bukkit.enchantments.Enchantment.MENDING;
public class ItemUtils {
public static boolean isContainer(ItemStack itemStack) {
return itemStack.getType() == Material.CHEST ||
itemStack.getType() == Material.TRAPPED_CHEST ||
itemStack.getType() == Material.FURNACE ||
itemStack.getType() == Material.BLAST_FURNACE ||
itemStack.getType() == Material.DROPPER ||
itemStack.getType() == Material.DISPENSER ||
itemStack.getType() == Material.HOPPER ||
itemStack.getType() == Material.BARREL;
}
public static Inventory getSubInventory(ItemStack containerItem) {
ServerUtils.verbose("NBT: GetSubInv checking item: " + containerItem);
if (containerItem.getItemMeta() instanceof BlockStateMeta blockStateMeta) {
ServerUtils.verbose("NBT: subInv has (is) blockStateMeta: " + blockStateMeta);
BlockState blockState = blockStateMeta.getBlockState();
if (blockState instanceof Container) {
ServerUtils.verbose("NBT: subInv has (is) container: " + (Container) blockState);
return ((Container) blockState).getInventory();
}
}
ServerUtils.verbose("NBT: Inv is null: " + containerItem);
return null;
}
public static boolean containerPasses(Inventory inventory) {
for (ItemStack itemStack : inventory.getContents()) {
if (itemStack == null || itemStack.getType().isAir()) continue;
if (!itemPasses(itemStack)) {
ServerUtils.verbose("NBT: No pass C(I)");
return false;
}
if (!isContainer(itemStack)) continue;
Inventory subInventory = getSubInventory(itemStack);
if (!containerPasses(subInventory)) {
ServerUtils.verbose("NBT: No pass C(R)");
return false;
}
}
ServerUtils.verbose("NBT: Item passes recursion check.");
return true;
}
public static boolean itemPasses(ItemStack i) {
ServerUtils.verbose("NBT: Checking if item passes: " + i.getItemMeta());
if (i.getItemMeta() == null) {
ServerUtils.verbose("NBT: Item passes because of no meta");
return true;
}
ServerUtils.verbose("NBT: Item meta isn't null");
ItemMeta meta = i.getItemMeta();
Inventory inv = getSubInventory(i);
if (inv != null) {
ServerUtils.verbose("NBT: Item has a SubInv: " + inv);
if (!containerPasses(inv)) {
ServerUtils.verbose("NBT: No pass C");
return false;
}
}
if (!Sentinel.nbtConfig.allowName && meta.hasDisplayName()) {
ServerUtils.verbose("NBT: No pass N");
return false;
}
if (!Sentinel.nbtConfig.allowLore && meta.hasLore()) {
ServerUtils.verbose("NBT: No Pass L ");
return false;
}
if (!Sentinel.nbtConfig.allowPotions && (i.getType().equals(Material.POTION) || i.getType().equals(Material.SPLASH_POTION) || i.getType().equals(Material.LINGERING_POTION))) {
ServerUtils.verbose("NBT: No pass P");
return false;
}
if (!Sentinel.nbtConfig.allowAttributes && meta.hasAttributeModifiers()) {
ServerUtils.verbose("NBT: No pass A");
return false;
}
if (Sentinel.nbtConfig.globalMaxEnchant != 0 && hasIllegalEnchants(i)) {
ServerUtils.verbose("NBT: No pass E");
return false;
}
ServerUtils.verbose("NBT: All checks passed");
return true;
}
public static boolean hasIllegalEnchants(ItemStack i) {
ServerUtils.verbose("NBT: Checking for illegal enchants");
if (i.hasItemMeta() && i.getItemMeta().hasEnchants()) {
final ItemMeta meta = i.getItemMeta();
final Map<Enchantment, Integer> enchantments = meta.getEnchants();
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
Enchantment enchantment = entry.getKey();
int level = entry.getValue();
if (level > Sentinel.nbtConfig.globalMaxEnchant || isOverLimit(enchantment, level)) {
return true;
}
}
}
return false;
}
public static boolean isOverLimit(Enchantment enchantment, int level) {
int maxLevel = Sentinel.nbtConfig.globalMaxEnchant; // Default to global max enchant
// Old code here
if (enchantment.equals(MENDING)) {
maxLevel = Sentinel.nbtConfig.maxMending;
} else if (enchantment.equals(Enchantment.UNBREAKING)) {
maxLevel = Sentinel.nbtConfig.maxUnbreaking;
} else if (enchantment.equals(Enchantment.VANISHING_CURSE)) {
maxLevel = Sentinel.nbtConfig.maxVanishing;
} else if (enchantment.equals(Enchantment.BINDING_CURSE)) {
maxLevel = Sentinel.nbtConfig.maxCurseOfBinding;
} else if (enchantment.equals(Enchantment.AQUA_AFFINITY)) {
maxLevel = Sentinel.nbtConfig.maxAquaAffinity;
} else if (enchantment.equals(Enchantment.PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxProtection;
} else if (enchantment.equals(Enchantment.BLAST_PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxBlastProtection;
} else if (enchantment.equals(Enchantment.DEPTH_STRIDER)) {
maxLevel = Sentinel.nbtConfig.maxDepthStrider;
} else if (enchantment.equals(Enchantment.FEATHER_FALLING)) {
maxLevel = Sentinel.nbtConfig.maxFeatherFalling;
} else if (enchantment.equals(Enchantment.FIRE_PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxFireProtection;
} else if (enchantment.equals(Enchantment.FROST_WALKER)) {
maxLevel = Sentinel.nbtConfig.maxFrostWalker;
} else if (enchantment.equals(Enchantment.PROJECTILE_PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxProjectileProtection;
} else if (enchantment.equals(Enchantment.RESPIRATION)) {
maxLevel = Sentinel.nbtConfig.maxRespiration;
} else if (enchantment.equals(Enchantment.SOUL_SPEED)) {
maxLevel = Sentinel.nbtConfig.maxSoulSpeed;
} else if (enchantment.equals(Enchantment.THORNS)) {
maxLevel = Sentinel.nbtConfig.maxThorns;
} else if (enchantment.equals(Enchantment.SWEEPING_EDGE)) {
maxLevel = Sentinel.nbtConfig.maxSweepingEdge;
} else if (enchantment.equals(Enchantment.SWIFT_SNEAK)) {
maxLevel = Sentinel.nbtConfig.maxSwiftSneak;
} else if (enchantment.equals(Enchantment.BANE_OF_ARTHROPODS)) {
maxLevel = Sentinel.nbtConfig.maxBaneOfArthropods;
} else if (enchantment.equals(Enchantment.FIRE_ASPECT)) {
maxLevel = Sentinel.nbtConfig.maxFireAspect;
} else if (enchantment.equals(Enchantment.LOOTING)) {
maxLevel = Sentinel.nbtConfig.maxLooting;
} else if (enchantment.equals(Enchantment.IMPALING)) {
maxLevel = Sentinel.nbtConfig.maxImpaling;
} else if (enchantment.equals(Enchantment.KNOCKBACK)) {
maxLevel = Sentinel.nbtConfig.maxKnockback;
} else if (enchantment.equals(Enchantment.SHARPNESS)) {
maxLevel = Sentinel.nbtConfig.maxSharpness;
} else if (enchantment.equals(Enchantment.SMITE)) {
maxLevel = Sentinel.nbtConfig.maxSmite;
} else if (enchantment.equals(Enchantment.CHANNELING)) {
maxLevel = Sentinel.nbtConfig.maxChanneling;
} else if (enchantment.equals(Enchantment.FLAME)) {
maxLevel = Sentinel.nbtConfig.maxFlame;
} else if (enchantment.equals(Enchantment.INFINITY)) {
maxLevel = Sentinel.nbtConfig.maxInfinity;
} else if (enchantment.equals(Enchantment.LOYALTY)) {
maxLevel = Sentinel.nbtConfig.maxLoyalty;
} else if (enchantment.equals(Enchantment.RIPTIDE)) {
maxLevel = Sentinel.nbtConfig.maxRiptide;
} else if (enchantment.equals(Enchantment.MULTISHOT)) {
maxLevel = Sentinel.nbtConfig.maxMultishot;
} else if (enchantment.equals(Enchantment.PIERCING)) {
maxLevel = Sentinel.nbtConfig.maxPiercing;
} else if (enchantment.equals(Enchantment.POWER)) {
maxLevel = Sentinel.nbtConfig.maxPower;
} else if (enchantment.equals(Enchantment.PUNCH)) {
maxLevel = Sentinel.nbtConfig.maxPunch;
} else if (enchantment.equals(Enchantment.QUICK_CHARGE)) {
maxLevel = Sentinel.nbtConfig.maxQuickCharge;
} else if (enchantment.equals(Enchantment.EFFICIENCY)) {
maxLevel = Sentinel.nbtConfig.maxEfficiency;
} else if (enchantment.equals(Enchantment.FORTUNE)) {
maxLevel = Sentinel.nbtConfig.maxFortune;
} else if (enchantment.equals(Enchantment.LUCK_OF_THE_SEA)) {
maxLevel = Sentinel.nbtConfig.maxLuckOfTheSea;
} else if (enchantment.equals(Enchantment.LURE)) {
maxLevel = Sentinel.nbtConfig.maxLure;
} else if (enchantment.equals(Enchantment.SILK_TOUCH)) {
maxLevel = Sentinel.nbtConfig.maxSilkTouch;
}
return level > maxLevel;
}
/*
public static boolean isOverLimit(Enchantment enchantment, int level) {
int maxLevel = Sentinel.nbtConfig.globalMaxEnchant; // Default to global max enchant
// New code here
switch (enchantment.getKey().getKey()) {
case "mending" -> maxLevel = Sentinel.nbtConfig.maxMending;
case "unbreaking" -> maxLevel = Sentinel.nbtConfig.maxUnbreaking;
}
// Old code here
if (enchantment.equals(MENDING)) {
maxLevel = Sentinel.nbtConfig.maxMending;
} else if (enchantment.equals(Enchantment.UNBREAKING)) {
maxLevel = Sentinel.nbtConfig.maxUnbreaking;
} else if (enchantment.equals(Enchantment.VANISHING_CURSE)) {
maxLevel = Sentinel.nbtConfig.maxVanishing;
} else if (enchantment.equals(Enchantment.BINDING_CURSE)) {
maxLevel = Sentinel.nbtConfig.maxCurseOfBinding;
} else if (enchantment.equals(Enchantment.AQUA_AFFINITY)) {
maxLevel = Sentinel.nbtConfig.maxAquaAffinity;
} else if (enchantment.equals(Enchantment.PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxProtection;
} else if (enchantment.equals(Enchantment.BLAST_PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxBlastProtection;
} else if (enchantment.equals(Enchantment.DEPTH_STRIDER)) {
maxLevel = Sentinel.nbtConfig.maxDepthStrider;
} else if (enchantment.equals(Enchantment.FEATHER_FALLING)) {
maxLevel = Sentinel.nbtConfig.maxFeatherFalling;
} else if (enchantment.equals(Enchantment.FIRE_PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxFireProtection;
} else if (enchantment.equals(Enchantment.FROST_WALKER)) {
maxLevel = Sentinel.nbtConfig.maxFrostWalker;
} else if (enchantment.equals(Enchantment.PROJECTILE_PROTECTION)) {
maxLevel = Sentinel.nbtConfig.maxProjectileProtection;
} else if (enchantment.equals(Enchantment.RESPIRATION)) {
maxLevel = Sentinel.nbtConfig.maxRespiration;
} else if (enchantment.equals(Enchantment.SOUL_SPEED)) {
maxLevel = Sentinel.nbtConfig.maxSoulSpeed;
} else if (enchantment.equals(Enchantment.THORNS)) {
maxLevel = Sentinel.nbtConfig.maxThorns;
} else if (enchantment.equals(Enchantment.SWEEPING_EDGE)) {
maxLevel = Sentinel.nbtConfig.maxSweepingEdge;
} else if (enchantment.equals(Enchantment.SWIFT_SNEAK)) {
maxLevel = Sentinel.nbtConfig.maxSwiftSneak;
} else if (enchantment.equals(Enchantment.BANE_OF_ARTHROPODS)) {
maxLevel = Sentinel.nbtConfig.maxBaneOfArthropods;
} else if (enchantment.equals(Enchantment.FIRE_ASPECT)) {
maxLevel = Sentinel.nbtConfig.maxFireAspect;
} else if (enchantment.equals(Enchantment.LOOTING)) {
maxLevel = Sentinel.nbtConfig.maxLooting;
} else if (enchantment.equals(Enchantment.IMPALING)) {
maxLevel = Sentinel.nbtConfig.maxImpaling;
} else if (enchantment.equals(Enchantment.KNOCKBACK)) {
maxLevel = Sentinel.nbtConfig.maxKnockback;
} else if (enchantment.equals(Enchantment.SHARPNESS)) {
maxLevel = Sentinel.nbtConfig.maxSharpness;
} else if (enchantment.equals(Enchantment.SMITE)) {
maxLevel = Sentinel.nbtConfig.maxSmite;
} else if (enchantment.equals(Enchantment.CHANNELING)) {
maxLevel = Sentinel.nbtConfig.maxChanneling;
} else if (enchantment.equals(Enchantment.FLAME)) {
maxLevel = Sentinel.nbtConfig.maxFlame;
} else if (enchantment.equals(Enchantment.INFINITY)) {
maxLevel = Sentinel.nbtConfig.maxInfinity;
} else if (enchantment.equals(Enchantment.LOYALTY)) {
maxLevel = Sentinel.nbtConfig.maxLoyalty;
} else if (enchantment.equals(Enchantment.RIPTIDE)) {
maxLevel = Sentinel.nbtConfig.maxRiptide;
} else if (enchantment.equals(Enchantment.MULTISHOT)) {
maxLevel = Sentinel.nbtConfig.maxMultishot;
} else if (enchantment.equals(Enchantment.PIERCING)) {
maxLevel = Sentinel.nbtConfig.maxPiercing;
} else if (enchantment.equals(Enchantment.POWER)) {
maxLevel = Sentinel.nbtConfig.maxPower;
} else if (enchantment.equals(Enchantment.PUNCH)) {
maxLevel = Sentinel.nbtConfig.maxPunch;
} else if (enchantment.equals(Enchantment.QUICK_CHARGE)) {
maxLevel = Sentinel.nbtConfig.maxQuickCharge;
} else if (enchantment.equals(Enchantment.EFFICIENCY)) {
maxLevel = Sentinel.nbtConfig.maxEfficiency;
} else if (enchantment.equals(Enchantment.FORTUNE)) {
maxLevel = Sentinel.nbtConfig.maxFortune;
} else if (enchantment.equals(Enchantment.LUCK_OF_THE_SEA)) {
maxLevel = Sentinel.nbtConfig.maxLuckOfTheSea;
} else if (enchantment.equals(Enchantment.LURE)) {
maxLevel = Sentinel.nbtConfig.maxLure;
} else if (enchantment.equals(Enchantment.SILK_TOUCH)) {
maxLevel = Sentinel.nbtConfig.maxSilkTouch;
}
return level > maxLevel;
}
*/
}

View File

@@ -0,0 +1,115 @@
package me.trouper.sentinel.utils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public class MathUtils {
public static double avg(Integer... ints) {
final List<Integer> list = Arrays.stream(ints).filter(Objects::nonNull).toList();
return avg(list);
}
public static double avg(List<Integer> ints) {
double sum = 0.0;
for (Integer i : ints) sum += i;
return sum / ints.size();
}
public static double round(double value, int nthPlace) {
return Math.floor(value * nthPlace) / nthPlace;
}
public static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
return result.toString();
}
public static String SHA256(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder(2 * encodedHash.length);
for (byte b : encodedHash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static String MD5(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder(2 * encodedHash.length);
for (byte b : encodedHash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static double calcSim(String s1, String s2) {
int maxLength = Math.max(s1.length(), s2.length());
if (maxLength == 0) {
return 100.0;
}
int distance = calculateLevenshteinDistance(s1, s2);
double similarity = ((double) (maxLength - distance) / maxLength) * 100.0;
return similarity;
}
public static int calculateLevenshteinDistance(String s1, String s2) {
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
dp[i][0] = i;
}
for (int j = 0; j <= s2.length(); j++) {
dp[0][j] = j;
}
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
int cost = (s1.charAt(i - 1) == s2.charAt(j - 1)) ? 0 : 1;
dp[i][j] = Math.min(Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + cost);
}
}
return dp[s1.length()][s2.length()];
}
}

View File

@@ -0,0 +1,14 @@
package me.trouper.sentinel.utils;
import me.trouper.sentinel.Sentinel;
import org.bukkit.entity.Player;
public class PlayerUtils {
public static boolean isTrusted(Player player) {
return Sentinel.mainConfig.plugin.trustedPlayers.contains(player.getUniqueId().toString());
}
public static boolean isTrusted(String uuid) {
return Sentinel.mainConfig.plugin.trustedPlayers.contains(uuid);
}
}

View File

@@ -0,0 +1,105 @@
package me.trouper.sentinel.utils;
import me.trouper.sentinel.Sentinel;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.metadata.MetadataValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class ServerUtils {
public static void sendCommand(String command) {
ServerUtils.verbose("Getting scheduler");
Bukkit.getScheduler().scheduleSyncDelayedTask(Sentinel.getInstance(), () -> {
try {
ServerUtils.verbose("Attempting to run command...");
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), command);
} catch (Exception e) {
e.printStackTrace();
}
},1);
}
public static void verbose(String message) {
if (Sentinel.mainConfig.debugMode) {
String log = "[Sentinel] [DEBUG]: " + message;
Sentinel.log.info(log);
for (Player trustedPlayer : Bukkit.getOnlinePlayers()) {
if (PlayerUtils.isTrusted(trustedPlayer)) {
trustedPlayer.sendMessage("§d§lSentinel §7[§bDEBUG§7] §8» §7" + message);
}
}
}
}
public static List<Player> getPlayers() {
return new ArrayList<>(Bukkit.getOnlinePlayers());
}
public static List<Player> getStaff() {
return getPlayers().stream().filter(Player -> Player.hasPermission("sentinel.staff")).toList();
}
public static void forEachPlayer(Consumer<Player> consumer) {
getPlayers().forEach(consumer);
}
public static void forEachStaff(Consumer<Player> consumer) {
getStaff().forEach(consumer);
}
public static void dmEachPlayer(Predicate<Player> condition, String dm) {
forEachPlayer(p -> {
if (condition.test(p)) p.sendMessage(dm);
});
}
public static void dmEachPlayer(String dm) {
forEachPlayer(p -> p.sendMessage(dm));
}
public static void forEachSpecified(Iterable<Player> players, Consumer<Player> consumer) {
players.forEach(consumer);
}
public static void forEachSpecified(Consumer<Player> consumer, Player... players) {
Arrays.stream(players).forEach(consumer);
}
public static void forEachPlayerRun(Predicate<Player> condition, Consumer<Player> task) {
forEachPlayer(p -> {
if (condition.test(p)) {
task.accept(p);
}
});
}
public static void sendActionBar(Player p, String msg) {
p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(msg));
}
public static boolean hasBlockBelow(Player player, Material material) {
for (int y = player.getLocation().getBlockY() - 1; y >= player.getLocation().getBlockY() - 12; y--) {
if (player.getWorld().getBlockAt(player.getLocation().getBlockX(), y, player.getLocation().getBlockZ()).getType() == material) {
return true;
}
}
return false;
}
public static boolean isVanished(Player player) {
for (MetadataValue meta : player.getMetadata("vanished")) {
if (meta.asBoolean()) return true;
}
return false;
}
public static String[] unVanishedPlayers() {
return io.github.itzispyder.pdk.utils.ServerUtils.players(ServerUtils::isVanished).stream().map(Player::getName).toArray(String[]::new);
}
}

View File

@@ -0,0 +1,115 @@
package me.trouper.sentinel.utils;
import me.trouper.sentinel.Sentinel;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class Text {
public static String removeColors(String input) {
return input.replaceAll("§[0-9a-fr]", "");
}
public static String regexHighlighter(String input, String regex, String startString, String endString) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(result, startString + matcher.group() + endString);
}
matcher.appendTail(result);
return result.toString();
}
public static final char SECTION_SYMBOL = (char)167;
public static String color(String msg) {
return msg.replace('&', SECTION_SYMBOL);
}
public static String prefix(String text) {
String prefix = Sentinel.mainConfig.plugin.prefix;
return color(prefix + text);
}
public static String removeFirstColor(String input) {
if (input.startsWith("\u00a7")) {
if (input.length() > 2) {
return input.substring(2);
} else {
return "";
}
} else {
return input;
}
}
public static String replaceRepeatingLetters(String input) {
if (input == null || input.isEmpty()) {
return input;
}
StringBuilder simplifiedText = new StringBuilder();
char currentChar = input.charAt(0);
int count = 1;
for (int i = 1; i < input.length(); i++) {
char nextChar = input.charAt(i);
if (Character.toLowerCase(nextChar) == Character.toLowerCase(currentChar)) {
count++;
} else {
simplifiedText.append(currentChar);
if (count > 1) {
simplifiedText.append(currentChar);
}
currentChar = nextChar;
count = 1;
}
}
simplifiedText.append(currentChar);
if (count > 1) {
simplifiedText.append(currentChar);
}
return simplifiedText.toString();
}
public static String fromLeetString(String s) {
Map<String, String> dictionary = Sentinel.advConfig.leetPatterns;
String msg = s;
for (String key : dictionary.keySet()) {
if (!s.contains(key)) continue;
try {
if (key.equals("$")) {
msg = msg.replaceAll("\\$", "s");
}
else {
msg = msg.replaceAll(key, dictionary.get(key));
}
}
catch (PatternSyntaxException ex) {
String regex = "[" + key + "]";
msg = msg.replaceAll(regex, dictionary.get(key));
}
}
return msg;
}
public static String cleanName(String type) {
return type.replaceAll("_"," ").toLowerCase();
}
}

View File

@@ -0,0 +1,62 @@
package me.trouper.sentinel.utils.trees;
import java.util.Map;
public class ConsoleFormatter {
public static String format(Node node) {
StringBuilder sb = new StringBuilder();
formatNode(sb, node, 0);
return sb.toString();
}
private static void formatNode(StringBuilder sb, Node node, int level) {
if (level == 0) {
sb.append("]==-- ").append(node.title).append(" --==[\n");
} else {
sb.append(node.title).append("\n");
}
for (String text : node.texts) {
text = text.replace("<hs>"," > ");
text = text.replace("<he>"," < ");
if (level == 0) {
sb.append(text).append("\n");
} else {
sb.append("").append(text).append("\n");
}
}
for (Map.Entry<String, String> entry : node.values.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
key = key.replace("<hs>"," > ");
key = key.replace("<he>"," < ");
value = value.replace("<hs>"," > ");
value = value.replace("<he>"," < ");
if (level == 0) {
sb.append(key).append(": ").append(value).append("\n");
} else {
sb.append("").append(key).append(": ").append(value).append("\n");
}
}
for (Map.Entry<String, String> entry : node.fields.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
key = key.replace("<hs>"," > ");
key = key.replace("<he>"," < ");
value = value.replace("<hs>"," > ");
value = value.replace("<he>"," < ");
if (level == 0) {
sb.append(key).append(":\n ").append(value).append("\n");
} else {
sb.append("").append(key).append(":\n ").append(value).append("\n");
}
}
for (Node child : node.children) {
formatNode(sb, child, level + 1);
}
}
}

View File

@@ -0,0 +1,94 @@
package me.trouper.sentinel.utils.trees;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
import io.github.itzispyder.pdk.utils.discord.DiscordWebhook;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.Emojis;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class EmbedFormatter {
public static void sendEmbed(DiscordEmbed embed) {
sendEmbed(embed,Sentinel.mainConfig.plugin.webhook);
}
public static boolean sendEmbed(DiscordEmbed embed, String spec) {
DiscordWebhook webhook = new DiscordWebhook("Sentinel Anti-Nuke Webhook Logger", "https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/1epkvziv.png","", false, embed);
AtomicBoolean success = new AtomicBoolean(false);
SchedulerUtils.later(0,()->{
try {
webhook.send(spec);
} catch (IOException e) {
Sentinel.log.warning(e.getMessage());
success.set(false);
return;
}
success.set(true);
});
return success.get();
}
public static DiscordEmbed format(Node node) {
DiscordEmbed.Builder eb = new DiscordEmbed.Builder();
StringBuilder desc = new StringBuilder();
formatNode(eb, node, desc,0);
eb.color(0xFFAB4D);
return eb.desc(desc.toString()).build();
}
private static void formatNode(DiscordEmbed.Builder eb, Node node, StringBuilder desc, int level) {
eb.author("Sentinel | Anti-Nuke","https://trouper.me/sentinel",null);
if (level == 0) {
eb.title("Incoming from server: %s".formatted(Sentinel.mainConfig.plugin.identifier));
} else {
desc.repeat(Emojis.space,level - 1).append("**").append(node.title).append("**\n");
}
for (String text : node.texts) {
text = text.replace("<hs>"," > ");
text = text.replace("<he>"," < ");
if (level == 0) {
desc.append(text).append("\n");
} else {
desc.repeat(Emojis.space,level - 1).append(Emojis.rightSort).append(text).append("\n");
}
}
for (Map.Entry<String, String> entry : node.values.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
key = key.replace("<hs>"," > ");
key = key.replace("<he>"," < ");
value = value.replace("<hs>"," > ");
value = value.replace("<he>"," < ");
if (level == 0) {
desc.append(key).append(": `").append(value).append("`\n");
} else {
desc.repeat(Emojis.space,level - 1).append(Emojis.rightSort).append(key).append(": `").append(value).append("`\n");
}
}
for (Map.Entry<String, String> entry : node.fields.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
key = key.replace("<hs>"," > ");
key = key.replace("<he>"," < ");
value = value.replace("<hs>"," > ");
value = value.replace("<he>"," < ");
if (level == 0) {
desc.append("**").append(key).append("**:\n `").append(value).append("`\n");
} else {
desc.repeat(Emojis.space,level - 1).append(Emojis.rightArrow).append("**").append(key).append("**:\n `").append(value).append("`\n");
}
}
for (Node child : node.children) {
formatNode(eb, child, desc,level + 1);
}
}
}

View File

@@ -0,0 +1,66 @@
package me.trouper.sentinel.utils.trees;
import me.trouper.sentinel.utils.Text;
import java.util.Map;
public class HoverFormatter {
public static String format(Node node) {
StringBuilder sb = new StringBuilder();
formatNode(sb, node, 0);
return Text.color(sb.toString());
}
private static void formatNode(StringBuilder sb, Node node, int level) {
if (level == 0) {
//sb.append("&#3B3B3B]&#565656=&#717171=&#8C8C8C-&#A7A7A7- &6&l").append(node.title).append("&r &#A7A7A7-&#8C8C8C-&#717171=&#565656=&#3B3B3B[\n");
sb.append("&8]==-- &6&l").append(node.title).append("&r &8--==[\n&r");
} else {
sb.append("&f&l").append(node.title).append("\n");
}
for (String text : node.texts) {
text = text.replace("<hs>","&e&n");
text = text.replace("<he>","&r&b");
if (level == 0) {
sb.append("&7").append(text).append("\n");
} else {
sb.append(" &8&l➥&r &7").append(text).append("\n");
}
}
for (Map.Entry<String, String> entry : node.values.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
key = key.replace("<hs>","&e&n");
key = key.replace("<he>","&r&b");
value = value.replace("<hs>","&e&n");
value = value.replace("<he>","&r&b");
if (level == 0) {
sb.append("&7").append(key).append("&8: &b").append(value).append("\n&r");
} else {
sb.append(" &8&l➥&r &7").append(key).append("&8: &b").append(value).append("\n&r");
}
}
for (Map.Entry<String, String> entry : node.fields.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
key = key.replace("<hs>","&e&n");
key = key.replace("<he>","&r&b");
value = value.replace("<hs>","&e&n");
value = value.replace("<he>","&r&b");
if (level == 0) {
sb.append("&7").append(key).append("&8:\n&b ").append(value).append("\n&r");
} else {
sb.append(" &8&l➥&r &7").append(key).append("&8:\n &b ").append(value).append("\n&r");
}
}
for (Node child : node.children) {
formatNode(sb, child, level + 1);
}
}
}

View File

@@ -0,0 +1,39 @@
package me.trouper.sentinel.utils.trees;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Node {
String title;
List<String> texts;
Map<String, String> values;
Map<String, String> fields;
List<Node> children;
public Node(String title) {
this.title = title;
this.texts = new ArrayList<>();
this.values = new HashMap<>();
this.fields = new HashMap<>();
this.children = new ArrayList<>();
}
public void addTextLine(String text) {
this.texts.add(text);
}
public void addKeyValue(String name, String value) {
this.values.put(name, value);
}
public void addField(String title, String value) {
this.fields.put(title,value);
}
public void addChild(Node child) {
this.children.add(child);
}
}