Made NBT Gui Async, Added sounds to most other GUIs.

This commit is contained in:
thetrouper
2025-03-22 01:24:37 -05:00
parent 0afbbc8549
commit 4069464e16
34 changed files with 188 additions and 197 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -54,12 +54,20 @@ dependencies {
implementation("de.tr7zw:item-nbt-api:2.14.1")
}
static def generateBuildId() {
return new Date().format('HH:mm:ss')
}
processResources {
filesMatching('plugin.yml') {
expand(version: project.version)
expand(
version: project.version,
build: generateBuildId()
)
}
}
task cleanPluginYml {
doLast {
def jarFile = shadowJar.archiveFile.get().asFile

View File

@@ -1,180 +0,0 @@
name: SentinelAntiNuke
version: '0.3.1'
main: me.trouper.sentinel.Sentinel
api-version: 1.21
authors: [ TheTrouper ]
description: Detect, Block, and Ban players who attempt to grief your server.
website: https://thetrouper.github.io/
softdepend:
- ProtocolLib
- ProtocolSupport
- ViaVersion
- ViaBackwards
- ViaRewind
- Geyser-Spigot
- NoChatReports
load: POSTWORLD
permissions:
sentinel.admin:
description: Allows access to all Sentinel admin commands.
default: op
children:
sentinel.debug: true
sentinel.extras: true
sentinel.staff:
description: Allows access to Sentinel staff commands.
default: op
children:
sentinel.socialspy: true
sentinel.false-positive: true
sentinel.false-positive:
description: Allows the user to manage false positives.
default: false
children:
sentinel.false-positive.add: true
sentinel.false-positive.remove: true
sentinel.false-positive.add:
description: Allows the user to add a false positive.
default: false
sentinel.false-positive.remove:
description: Allows the user to remove a false positive.
default: false
sentinel.debug:
description: Allows the user to toggle debug mode.
default: op
sentinel.extras:
description: Sentinel Extra Features
default: op
sentinel.commandblock:
description: Allows the user to manage command blocks.
default: false
sentinel.socialspy:
description: Allows the user to spy on social interactions.
default: false
sentinel.callbacks:
description: Allows access to all Sentinel callback commands.
default: op
children:
sentinel.callbacks.fpreport: true
sentinel.callbacks.fpreport:
description: Allows the user to report false positives.
default: false
sentinel.message:
description: Allows the user to send messages.
default: true
sentinel.reply:
description: Allows the user to reply to messages.
default: true
sentinel.chatfilter:
description: Parent permission for all chat-related features.
default: false
children:
sentinel.chatfilter.profanity: true
sentinel.chatfilter.spam: true
sentinel.chatfilter.unicode: true
sentinel.chatfilter.url: true
sentinel.chatfilter.profanity:
description: Parent permission for profanity filter features.
default: false
children:
sentinel.chatfilter.profanity.view: true
sentinel.chatfilter.profanity.bypass: true
sentinel.chatfilter.profanity.view:
description: Allows the user to view profanity filter logs.
default: false
sentinel.chatfilter.profanity.bypass:
description: Allows the user to bypass the profanity filter.
default: false
sentinel.chatfilter.spam:
description: Parent permission for spam filter features.
default: false
children:
sentinel.chatfilter.spam.view: true
sentinel.chatfilter.spam.bypass: true
sentinel.chatfilter.spam.view:
description: Allows the user to view spam filter logs.
default: false
sentinel.chatfilter.spam.bypass:
description: Allows the user to bypass the spam filter.
default: false
sentinel.chatfilter.unicode:
description: Parent permission for unicode filter features.
default: false
children:
sentinel.chatfilter.unicode.view: true
sentinel.chatfilter.unicode.bypass: true
sentinel.chatfilter.unicode.view:
description: Allows the user to view unicode filter logs.
default: false
sentinel.chatfilter.unicode.bypass:
description: Allows the user to bypass the unicode filter.
default: false
sentinel.chatfilter.url:
description: Parent permission for URL filter features.
default: false
children:
sentinel.chatfilter.url.view: true
sentinel.chatfilter.url.bypass: true
sentinel.chatfilter.url.view:
description: Allows the user to view URL filter logs.
default: false
sentinel.chatfilter.url.bypass:
description: Allows the user to bypass the URL filter.
default: false
commands:
sentinel:
description: Main command for Sentinel.
usage: /sentinel <reload|config|false-positive|debug|commandblock|socialspy>
permission: sentinel.staff
permission-message: You do not have permission to use this command.
sentinelextras:
usage: /sentinelextras [alfa|bravo|charlie|delta|echo|foxtrot|golf|hotel|india|juliett] <player>
description: Extra features for sentinel.
permission: sentinel.extra
permission-message: You do not have permission to use this command.
sentinelcallback:
description: Callback command for Sentinel.
usage: /callback <fpreport>
permission: sentinel.callbacks
permission-message: You do not have permission to use this command.
message:
description: Send a message to another player.
usage: /message <player> <message>
permission: sentinel.message
permission-message: You do not have permission to use this command.
aliases:
- msg
- etell
- tell
- t
- ewhisper
- whisper
- w
- privatemessage
- pm
- m
- directmessage
- dm
- sentinelmessage
- sm
- stell
- smsg
reply:
description: Reply to a message.
usage: /reply <message>
permission: sentinel.reply
permission-message: You do not have permission to use this command.
aliases:
- r
- er
- rply
- ereply
- sr
- sreply
- sentinelreply
sentineltab:
description: tab completion redirects for sentinel
usage: /sentineltab [<args>]
reop:
description: Allows trusted players to elevate their permissions
usage: /reop

View File

@@ -1,7 +1,7 @@
# Plugin
group = 'me.trouper'
version = 0.3.1
version = 1.0.0
# Minecraft
mc_version = 1.21

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -28,6 +28,8 @@ public final class Sentinel extends JavaPlugin {
public String nonce;
public String ip;
public int port;
public String version;
public String build;
/* ]=- Sentinel Startup Flow -=[
Make sure everything is done in sequence to avoid NullPointerException!
@@ -51,6 +53,9 @@ public final class Sentinel extends JavaPlugin {
@Override
public void onLoad() {
version = getPluginMeta().getVersion().split("\\-")[0];
build = getPluginMeta().getVersion().split("\\-")[1];
getLogger().info("Build ID: %s".formatted(build));
getLogger().info("\n]======------ Pre-load started ------======[");
getLogger().info("Setting PacketEvents API");
@@ -97,7 +102,7 @@ public final class Sentinel extends JavaPlugin {
public void onDisable() {
// Plugin shutdown logic
PacketEvents.getAPI().terminate();
getLogger().info("Sentinel has disabled! (%s) Your server is now no longer protected!".formatted(getDescription().getVersion()));
getLogger().info("Sentinel has disabled! (%s) Your server is now no longer protected!".formatted(version));
}
public static Sentinel getInstance() {

View File

@@ -12,6 +12,7 @@ public class MainConfig implements JsonSerializable<MainConfig> {
public transient String user = "%%__USER__%%";
public transient String username = "%%__USERNAME__%%";
@Override
public File getFile() {
File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/main-config.json");

View File

@@ -40,10 +40,10 @@ public class Items {
.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("&bVersion&7: &f%s".formatted(Sentinel.getInstance().version)))
.lore(Text.color("&bLicensed to&7: &f%s".formatted(Sentinel.getInstance().nonce)))
.lore(" ")
.lore(Text.color("&e&nAuthor(s)&r&e: &e%s").formatted(Sentinel.getInstance().getDescription().getAuthors()))
.lore(Text.color("&e&nAuthor(s)&r&e: &e%s").formatted(Sentinel.getInstance().getPluginMeta().getAuthors()))
.enchant(Enchantment.PROTECTION,64)
.flag(ItemFlag.HIDE_ENCHANTS)
.build();

View File

@@ -7,6 +7,8 @@ import me.trouper.sentinel.server.gui.nbt.NBTGui;
import me.trouper.sentinel.server.gui.whitelist.WhitelistGUI;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
@@ -31,13 +33,16 @@ public class MainGUI {
.build();
private void openWhitelist(InventoryClickEvent e) {
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
e.getWhoClicked().openInventory(new WhitelistGUI().createGUI((Player) e.getWhoClicked()).getInventory());
}
private void openNBT(InventoryClickEvent e) {
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
e.getWhoClicked().openInventory(new NBTGui().createGUI((Player) e.getWhoClicked()).getInventory());
}
private void openConfig(InventoryClickEvent e) {
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
}

View File

@@ -5,14 +5,11 @@ import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@@ -79,11 +76,13 @@ public abstract class PaginatedGUI<T> {
Bukkit.getScheduler().runTask(Sentinel.getInstance(), () -> {
inv.setItem(slot, displayItem);
if (runAsynchronously) p.playSound(p, Sound.UI_HUD_BUBBLE_POP, SoundCategory.MASTER,1,1.1F);
if (remaining.decrementAndGet() == 0) {
// Update remaining main slots and bottom slots to lime
for (int bottomSlot : new int[]{46, 47, 48, 50, 51, 52}) {
inv.setItem(bottomSlot, createPlaceholderItem(false));
}
if (runAsynchronously) p.playSound(p,Sound.BLOCK_NOTE_BLOCK_CHIME, SoundCategory.MASTER,1,0.8F);
}
});
}
@@ -94,6 +93,7 @@ public abstract class PaginatedGUI<T> {
for (int bottomSlot : new int[]{46, 47, 48, 50, 51, 52}) {
inv.setItem(bottomSlot, createPlaceholderItem(false));
}
if (runAsynchronously) p.playSound(p,Sound.BLOCK_NOTE_BLOCK_CHIME, SoundCategory.MASTER,1,0.8F);
});
}
};
@@ -123,6 +123,7 @@ public abstract class PaginatedGUI<T> {
addFilterItems(filterGui, p, filters);
p.openInventory(filterGui.build().getInventory());
p.playSound(p,Sound.BLOCK_NOTE_BLOCK_BELL, SoundCategory.MASTER,1,0.8F);
}
protected abstract void addFilterItems(CustomGui.GuiBuilder filterGui, Player p, Set<String> filters);
@@ -130,19 +131,31 @@ public abstract class PaginatedGUI<T> {
protected void toggleFilter(Player p, String filter) {
Set<String> filters = activeFilters.computeIfAbsent(p.getUniqueId(), k -> new HashSet<>());
ServerUtils.verbose("%s is now toggling the %s filter. Current %s", p, filter, filters);
if (filters.contains(filter)) filters.remove(filter);
else filters.add(filter);
if (filters.contains(filter)) {
filters.remove(filter);
p.playSound(p,Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
} else {
filters.add(filter);
p.playSound(p,Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1F);
}
ServerUtils.verbose("Current filters for %s: %s", p, filters);
openFilterMenu(p);
}
protected int getFilterCount(Player p) {
return activeFilters.getOrDefault(p.getUniqueId(), new HashSet<>()).size();
protected int getFilteredCount(Player p) {
return filterEntries(p,chosenOperator.getOrDefault(p.getUniqueId(),FilterOperator.AND)).size();
}
private int getFilterCount(Player p) {
return activeFilters.get(p.getUniqueId()).size();
}
protected void changePage(Player p, int direction) {
int current = currentPages.getOrDefault(p.getUniqueId(), 0);
if (current + direction < 0) {
p.playSound(p, Sound.ITEM_BOOK_PAGE_TURN, SoundCategory.MASTER,1,0.8F);
p.openInventory(backGUI().getInventory());
return;
}

View File

@@ -5,6 +5,8 @@ import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.config.chat.ChatGUI;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
@@ -16,12 +18,15 @@ public class ConfigGUI {
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(12, Items.ANTI_NUKE_CONFIG, e->{
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.define(14,Items.CHAT_CONFIG,e->{
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.define(26,Items.BACK,e->{
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.ITEM_BOOK_PAGE_TURN, SoundCategory.MASTER,1,1.1F);
e.getWhoClicked().openInventory(new MainGUI().home.getInventory());
})
.build();

View File

@@ -8,6 +8,8 @@ import me.trouper.sentinel.server.gui.config.ConfigGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
@@ -20,6 +22,7 @@ public class ChatGUI {
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26,Items.BACK,e->{
((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.ITEM_BOOK_PAGE_TURN, SoundCategory.MASTER,1,1.3F);
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
})
.define(16,PROFANITY_FILTER,e->{

View File

@@ -0,0 +1,128 @@
package me.trouper.sentinel.server.gui.nbt;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.storage.NBTStorage;
import me.trouper.sentinel.server.gui.MainGUI;
import me.trouper.sentinel.server.gui.PaginatedGUI;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
public class NBTGui
extends PaginatedGUI<Map.Entry<String, String>> {
private final NBTStorage nbtStorage;
public NBTGui() {
this.nbtStorage = Sentinel.getInstance().getDirector().io.nbtStorage;
}
@Override
protected boolean isAsynchronous() {
return true;
}
@Override
protected CustomGui backGUI() {
return new MainGUI().home;
}
@Override
protected String getTitle(Player p) {
return Text.color("&6&lCaught NBT &7(%s/%s filtered)".formatted(this.getFilteredCount(p), Sentinel.getInstance().getDirector().io.nbtStorage.caughtItems.size()));
}
@Override
protected void handleMainClick(Player p, InventoryClickEvent e) {
e.setCancelled(true);
MainGUI.verify(p);
Map.Entry<String, String> entry;
ItemStack item;
List<Map.Entry<String, String>> filtered;
int slot = e.getSlot();
if (slot >= 45) {
return;
}
if (e.getInventory().getItem(slot) == null) {
return;
}
int page = currentPages.compute(p.getUniqueId(), (k, v) -> this.realizePage(p, v == null ? 0 : v));
int index = page * 45 + slot;
if (index < (filtered = this.filterEntries(p, chosenOperator.computeIfAbsent(p.getUniqueId(), v -> PaginatedGUI.FilterOperator.AND))).size() && (item = NBTStorage.getItem((entry = filtered.get(index)).getKey())) != null) {
if (e.isLeftClick()) {
p.getInventory().addItem(item);
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_PICKUP, 1.0f, 1.0f);
} else if (e.isRightClick() && this.nbtStorage.deleteItem(entry.getKey())) {
p.playSound(p.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1.0f, 2.0f);
e.getClickedInventory().setItem(slot, ItemBuilder.create()
.material(Material.STRUCTURE_VOID)
.name(Text.color("&cDeleted Item"))
.lore(Text.color("&7You have deleted this item."))
.lore(Text.color("&7This will disappear next refresh."))
.build());
}
}
}
@Override
protected ItemStack createDisplayItem(Map.Entry<String, String> entry) {
ItemStack item = NBTStorage.getItem(entry.getKey());
if (item == null) {
return null;
}
ArrayList<String> lore = new ArrayList<>();
lore.add(Text.color("&7NBT Name: " + LegacyComponentSerializer.legacyAmpersand().serialize(item.effectiveName())));
lore.add("");
lore.add(Text.color("&7Owner: " + Bukkit.getOfflinePlayer(UUID.fromString(entry.getValue())).getName()));
lore.add("");
lore.add(Text.color("&eLeft-Click to give item"));
lore.add(Text.color("&eRight-Click to delete item"));
return new ItemBuilder().material(item.getType()).name(Text.color("&b" + item.getType().name())).lore(lore).build();
}
@Override
protected void addFilterItems(CustomGui.GuiBuilder filterGui, Player p, Set<String> filters) {
}
@Override
protected List<Map.Entry<String, String>> filterEntries(Player p, PaginatedGUI.FilterOperator operator) {
Set filters = activeFilters.computeIfAbsent(p.getUniqueId(), k -> new HashSet());
ServerUtils.verbose("Filtering entries for %s. Current: ", p, filters.toString());
return this.nbtStorage.caughtItems.entrySet().stream().filter(entry -> {
if (filters.isEmpty()) {
return true;
}
boolean result = operator == PaginatedGUI.FilterOperator.AND;
Iterator iterator = filters.iterator();
while (iterator.hasNext()) {
String filter;
boolean conditionMet = switch (filter = (String)iterator.next()) {
case "OWNER" -> (entry.getValue()).equals(p.getUniqueId().toString());
default -> false;
};
result = operator.apply(result, conditionMet);
if (operator == PaginatedGUI.FilterOperator.AND && !result) {
return false;
}
if (operator != PaginatedGUI.FilterOperator.OR || !result) continue;
return true;
}
return result;
}).collect(Collectors.toList());
}
}

View File

@@ -39,11 +39,13 @@ public class WhitelistGUI extends PaginatedGUI<CommandBlockHolder> {
@Override
protected String getTitle(Player p) {
return Text.color("&6&lCommand Blocks &7(%s/%s filtered)".formatted(getFilterCount(p),Sentinel.getInstance().getDirector().io.commandBlocks.holders.size()));
return Text.color("&6&lCommand Blocks &7(%s/%s filtered)".formatted(getFilteredCount(p),Sentinel.getInstance().getDirector().io.commandBlocks.holders.size()));
}
@Override
protected void handleMainClick(Player p, InventoryClickEvent e) {
e.setCancelled(true);
MainGUI.verify(p);
int slot = e.getSlot();
if (slot >= 45) return;
if (e.getInventory().getItem(slot) == null) return;

View File

@@ -137,7 +137,7 @@ public final class Loader {
setLite(false);
// Plugin startup logic
Sentinel.getInstance().getLogger().info("Starting Up! (%s)...".formatted(Sentinel.getInstance().getDescription().getVersion()));
Sentinel.getInstance().getLogger().info("Starting Up! (%s)...".formatted(Sentinel.getInstance().version));
// Commands
if (coldStart) new SentinelCommand().register();

View File

@@ -1,8 +1,9 @@
name: SentinelAntiNuke
version: '${version}'
version: '${version}-${build}'
main: me.trouper.sentinel.Sentinel
api-version: 1.21
authors: [ TheTrouper ]
prefix: 'Sentinel'
description: Detect, Block, and Ban players who attempt to grief your server.
website: https://thetrouper.github.io/
softdepend: