Auction Blacklist System

This commit is contained in:
Kam committed 2026-01-24 16:03:54 -05:00
1 parent b85804af98
commit fe998ea31c
10 files changed
+756 -240

No files matched your search

@@ -2,9 +2,16 @@ package foxz.command;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import java.util.List;
/**
* @deprecated The /noppes command is deprecated and no longer supported.
* Please use the /kam command instead for all CNPC+ operations.
*/
@Deprecated
public class CommandNoppes extends CommandBase {
public CmdNoppes noppes = new CmdNoppes(this);
@@ -21,6 +28,15 @@ public class CommandNoppes extends CommandBase {
@Override
public void processCommand(ICommandSender var1, String[] var2) {
// Send deprecation warning
var1.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[DEPRECATED] " +
EnumChatFormatting.YELLOW + "The /noppes command is deprecated and no longer supported."));
var1.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
"Please use " + EnumChatFormatting.GREEN + "/kam" + EnumChatFormatting.YELLOW + " commands instead."));
var1.addChatMessage(new ChatComponentText(EnumChatFormatting.GRAY +
"Type " + EnumChatFormatting.WHITE + "/kam help" + EnumChatFormatting.GRAY + " for available commands."));
// Still execute the command for backwards compatibility
noppes.processCommand(var1, var2);
}
@@ -1,9 +1,9 @@
package kamkeel.npcs.command;
import kamkeel.npcs.command.auction.BlacklistSubCommand;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import noppes.npcs.NoppesUtilServer;
import noppes.npcs.config.ConfigMarket;
import noppes.npcs.constants.EnumGuiType;
@@ -21,6 +21,11 @@ import static kamkeel.npcs.util.ColorUtil.sendResult;
public class AuctionCommand extends CommandKamkeelBase {
public AuctionCommand() {
super();
registerNestedCommand(new BlacklistSubCommand());
}
@Override
public String getCommandName() {
return "auction";
@@ -158,10 +163,17 @@ public class AuctionCommand extends CommandKamkeelBase {
}
@Override
public List addTabCompletionOptions(ICommandSender par1, String[] args) {
public List addTabCompletionOptions(ICommandSender sender, String[] args) {
if (args.length == 1) {
return getListOfStringsMatchingLastWord(args, new String[]{"list", "view", "open"});
return getListOfStringsMatchingLastWord(args, getAllSubCommandNames());
}
// Delegate to nested commands for deeper tab completion
List nestedCompletions = getNestedTabCompletions(sender, args);
if (nestedCompletions != null) {
return nestedCompletions;
}
return null;
}
}
@@ -11,13 +11,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public abstract class CommandKamkeelBase extends CommandBase {
public Map<String, Method> subcommands = new HashMap<String, Method>();
public Map<String, CommandKamkeelBase> nestedCommands = new HashMap<String, CommandKamkeelBase>();
public CommandKamkeelBase() {
for (Method m : this.getClass().getDeclaredMethods()) {
@@ -31,6 +29,14 @@ public abstract class CommandKamkeelBase extends CommandBase {
}
}
/**
* Register a nested command class as a subcommand.
* The nested command's getCommandName() becomes the subcommand name.
*/
public void registerNestedCommand(CommandKamkeelBase command) {
nestedCommands.put(command.getCommandName().toLowerCase(), command);
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
@@ -51,7 +57,7 @@ public abstract class CommandKamkeelBase extends CommandBase {
}
public boolean runSubCommands() {
return !subcommands.isEmpty();
return !subcommands.isEmpty() || !nestedCommands.isEmpty();
}
@Retention(value = RetentionPolicy.RUNTIME)
@@ -71,6 +77,22 @@ public abstract class CommandKamkeelBase extends CommandBase {
}
public void processSubCommand(ICommandSender sender, String command, String[] args) throws CommandException {
// Check nested commands first
CommandKamkeelBase nested = nestedCommands.get(command.toLowerCase());
if (nested != null) {
if (!canSendNestedCommand(sender, nested)) {
throw new CommandException("You are not allowed to use this command: " + command);
}
if (args.length == 0 || !nested.runSubCommands()) {
nested.processCommand(sender, args);
} else {
nested.processSubCommand(sender, args[0], Arrays.copyOfRange(args, 1, args.length));
}
return;
}
// Fall back to method subcommands
Method m = subcommands.get(command.toLowerCase());
if (m == null)
throw new CommandException("Unknown subcommand " + command);
@@ -132,4 +154,55 @@ public abstract class CommandKamkeelBase extends CommandBase {
return false;
}
public boolean canSendNestedCommand(ICommandSender sender, CommandKamkeelBase nested) {
int permission = nested.getRequiredPermissionLevel();
String subCommand = nested.getCommandName();
if (sender.canCommandSenderUseCommand(permission, getSubUniversalPermission())) {
return true;
}
if (sender.canCommandSenderUseCommand(permission, getSubCommandPermission(subCommand))) {
return true;
}
if (sender instanceof EntityPlayer) {
return CustomNpcsPermissions.hasCustomPermission((EntityPlayer) sender, getSubCommandPermission(subCommand));
}
return false;
}
// =========================================
// Tab Completion Helpers
// =========================================
/**
* Get all subcommand names (both method-based and nested)
*/
public String[] getAllSubCommandNames() {
Set<String> names = new HashSet<>();
names.addAll(subcommands.keySet());
names.addAll(nestedCommands.keySet());
return names.toArray(new String[0]);
}
/**
* Get tab completions for nested command at given depth
*/
public List getNestedTabCompletions(ICommandSender sender, String[] args) {
if (args.length == 0) return null;
String subCmd = args[0].toLowerCase();
CommandKamkeelBase nested = nestedCommands.get(subCmd);
if (nested != null && args.length > 1) {
// Delegate to nested command
String[] nestedArgs = Arrays.copyOfRange(args, 1, args.length);
return nested.addTabCompletionOptions(sender, nestedArgs);
}
return null;
}
}
@@ -0,0 +1,226 @@
package kamkeel.npcs.command.auction;
import kamkeel.npcs.command.CommandKamkeelBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import noppes.npcs.controllers.data.AuctionBlacklist;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendMessage;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class BlacklistSubCommand extends CommandKamkeelBase {
@Override
public String getCommandName() {
return "blacklist";
}
@Override
public String getDescription() {
return "Manage auction item blacklist";
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
// Show help when called with no subcommand
sendHelp(sender);
}
private void sendHelp(ICommandSender sender) {
sendMessage(sender, "\u00A76=== Auction Blacklist Commands ===");
sendMessage(sender, "\u00A7e/cnpc auction blacklist add <item|mod|nbt> <value>");
sendMessage(sender, "\u00A7e/cnpc auction blacklist remove <item|mod|nbt> <value>");
sendMessage(sender, "\u00A7e/cnpc auction blacklist list [item|mod|nbt]");
sendMessage(sender, "\u00A7e/cnpc auction blacklist reload");
sendMessage(sender, "\u00A7e/cnpc auction blacklist check \u00A77(checks held item)");
}
@SubCommand(
desc = "Add item, mod, or NBT tag to blacklist",
usage = "<item|mod|nbt> <value>"
)
public void add(ICommandSender sender, String[] args) throws CommandException {
if (args.length < 2) {
sendError(sender, "Usage: /cnpc auction blacklist add <item|mod|nbt> <value>");
return;
}
String type = args[0].toLowerCase();
String value = args[1];
switch (type) {
case "item":
if (AuctionBlacklist.addItem(value)) {
sendResult(sender, "Added item to blacklist: " + value);
} else {
sendError(sender, "Failed to add item to blacklist");
}
break;
case "mod":
if (AuctionBlacklist.addMod(value)) {
sendResult(sender, "Added mod to blacklist: " + value);
} else {
sendError(sender, "Failed to add mod to blacklist");
}
break;
case "nbt":
if (AuctionBlacklist.addNBTTag(value)) {
sendResult(sender, "Added NBT tag to blacklist: " + value);
} else {
sendError(sender, "Failed to add NBT tag to blacklist");
}
break;
default:
sendError(sender, "Unknown type: " + type + ". Use: item, mod, or nbt");
}
}
@SubCommand(
desc = "Remove item, mod, or NBT tag from blacklist",
usage = "<item|mod|nbt> <value>"
)
public void remove(ICommandSender sender, String[] args) throws CommandException {
if (args.length < 2) {
sendError(sender, "Usage: /cnpc auction blacklist remove <item|mod|nbt> <value>");
return;
}
String type = args[0].toLowerCase();
String value = args[1];
switch (type) {
case "item":
if (AuctionBlacklist.removeItem(value)) {
sendResult(sender, "Removed item from blacklist: " + value);
} else {
sendError(sender, "Item not found in blacklist: " + value);
}
break;
case "mod":
if (AuctionBlacklist.removeMod(value)) {
sendResult(sender, "Removed mod from blacklist: " + value);
} else {
sendError(sender, "Mod not found in blacklist: " + value);
}
break;
case "nbt":
if (AuctionBlacklist.removeNBTTag(value)) {
sendResult(sender, "Removed NBT tag from blacklist: " + value);
} else {
sendError(sender, "NBT tag not found in blacklist: " + value);
}
break;
default:
sendError(sender, "Unknown type: " + type + ". Use: item, mod, or nbt");
}
}
@SubCommand(
desc = "List blacklisted items, mods, or NBT tags",
usage = "[item|mod|nbt]"
)
public void list(ICommandSender sender, String[] args) throws CommandException {
String filter = args.length > 0 ? args[0].toLowerCase() : "all";
if (filter.equals("all") || filter.equals("item")) {
List<String> items = AuctionBlacklist.getBlacklistedItems();
sendMessage(sender, "\u00A76=== Blacklisted Items (" + items.size() + ") ===");
if (items.isEmpty()) {
sendMessage(sender, "\u00A77 (none)");
} else {
for (String item : items) {
sendMessage(sender, "\u00A7e " + item);
}
}
}
if (filter.equals("all") || filter.equals("mod")) {
List<String> mods = AuctionBlacklist.getBlacklistedMods();
sendMessage(sender, "\u00A76=== Blacklisted Mods (" + mods.size() + ") ===");
if (mods.isEmpty()) {
sendMessage(sender, "\u00A77 (none)");
} else {
for (String mod : mods) {
sendMessage(sender, "\u00A7e " + mod);
}
}
}
if (filter.equals("all") || filter.equals("nbt")) {
List<String> tags = AuctionBlacklist.getBlacklistedNBTTags();
sendMessage(sender, "\u00A76=== Blacklisted NBT Tags (" + tags.size() + ") ===");
if (tags.isEmpty()) {
sendMessage(sender, "\u00A77 (none)");
} else {
for (String tag : tags) {
sendMessage(sender, "\u00A7e " + tag);
}
}
}
sendMessage(sender, "\u00A77Note: Soulbound and Profile-Slotbound items are always blocked.");
}
@SubCommand(
desc = "Reload blacklist from config"
)
public void reload(ICommandSender sender, String[] args) throws CommandException {
AuctionBlacklist.reload();
sendResult(sender, "Blacklist reloaded from config");
}
@SubCommand(
desc = "Check if held item is blacklisted",
permission = 0
)
public void check(ICommandSender sender, String[] args) throws CommandException {
if (!(sender instanceof EntityPlayer)) {
sendError(sender, "This command can only be used by players");
return;
}
EntityPlayer player = (EntityPlayer) sender;
ItemStack heldItem = player.getHeldItem();
if (heldItem == null) {
sendError(sender, "You are not holding an item");
return;
}
String registryName = AuctionBlacklist.getRegistryName(heldItem);
sendMessage(sender, "\u00A76=== Blacklist Check ===");
sendMessage(sender, "\u00A77Item: \u00A7e" + heldItem.getDisplayName());
sendMessage(sender, "\u00A77Registry: \u00A7e" + (registryName != null ? registryName : "unknown"));
boolean isBlacklisted = AuctionBlacklist.isBlacklisted(heldItem);
boolean canBypass = AuctionBlacklist.canBypass(player);
if (isBlacklisted) {
sendMessage(sender, "\u00A7cStatus: BLACKLISTED");
if (canBypass) {
sendMessage(sender, "\u00A7aYou have bypass permission");
}
} else {
sendMessage(sender, "\u00A7aStatus: ALLOWED");
}
}
@Override
public List addTabCompletionOptions(ICommandSender sender, String[] args) {
if (args.length == 1) {
return getListOfStringsMatchingLastWord(args, getAllSubCommandNames());
}
if (args.length == 2) {
String subCmd = args[0].toLowerCase();
if (subCmd.equals("add") || subCmd.equals("remove") || subCmd.equals("list")) {
return getListOfStringsMatchingLastWord(args, new String[]{"item", "mod", "nbt"});
}
}
return null;
}
}
@@ -13,6 +13,7 @@ public class ConfigMarket {
public final static String CURRENCY = "Market.Currency";
public final static String AUCTION = "Market.Auction";
public final static String AUCTION_BLACKLIST = "Market.Auction.Blacklist";
public final static String AUCTION_LOGGING = "Market.Auction.Logging";
// Max trades grid = 9x5 = 45 slots
@@ -41,6 +42,14 @@ public class ConfigMarket {
public static double MinBidIncrementPercent = 0.05;
public static double CancellationPenaltyPercent = 0.10;
// =========================================
// Auction Blacklist Settings
// =========================================
public static boolean BlacklistEnabled = true;
public static String[] BlacklistedItems = new String[]{};
public static String[] BlacklistedMods = new String[]{};
public static String[] BlacklistedNBTTags = new String[]{};
// =========================================
// Auction Logging Settings
// =========================================
@@ -113,6 +122,45 @@ public class ConfigMarket {
CancellationPenaltyPercent = config.get(AUCTION, "Cancellation Penalty Percent", 0.10,
"Percentage of current bid taken as penalty when seller cancels an auction with bids (0.10 = 10%)").getDouble(0.10);
// =========================================
// Auction Blacklist Settings
// =========================================
config.setCategoryComment(AUCTION_BLACKLIST,
"Item Blacklist settings for the Auction House.\n" +
"Prevents specific items, mods, or items with certain NBT tags from being listed.\n\n" +
"ITEM FORMAT: Use 'modid:itemname' format (e.g., 'minecraft:bedrock', 'customnpcs:npcWand')\n" +
"WILDCARDS: Use * for wildcards (e.g., 'customnpcs:npc*' blocks all items starting with 'npc')\n" +
"MOD FORMAT: Use just the mod ID (e.g., 'projecte' blocks all items from that mod)\n" +
"NBT FORMAT: Use the NBT tag key name (e.g., 'AdminOnly' blocks items with that tag)");
BlacklistEnabled = config.get(AUCTION_BLACKLIST, "Enable Blacklist", true,
"Enable item blacklist checking when creating listings").getBoolean(true);
BlacklistedItems = config.get(AUCTION_BLACKLIST, "Blacklisted Items", new String[]{
"minecraft:bedrock",
"minecraft:command_block",
"customnpcs:npcWand",
"customnpcs:npcMobCloner",
"customnpcs:npcScripter",
"customnpcs:npcMovingPath",
"customnpcs:npcMounter",
"customnpcs:npcTeleporter",
"customnpcs:npcTool",
"customnpcs:npcSoulstoneFilled"
},
"Items that cannot be listed on the Auction House.\n" +
"Format: modid:itemname (supports * wildcards)\n" +
"Example: 'minecraft:diamond_sword' or 'customnpcs:npc*'").getStringList();
BlacklistedMods = config.get(AUCTION_BLACKLIST, "Blacklisted Mods", new String[]{},
"All items from these mods are blocked from the Auction House.\n" +
"Format: modid (e.g., 'projecte', 'thaumcraft')").getStringList();
BlacklistedNBTTags = config.get(AUCTION_BLACKLIST, "Blacklisted NBT Tags", new String[]{},
"Items containing any of these NBT tag keys are blocked.\n" +
"Checks the root level of the item's NBT compound.\n" +
"Example: 'AdminOnly', 'CreativeMode'").getStringList();
// =========================================
// Auction Logging Settings
// =========================================
@@ -163,6 +211,13 @@ public class ConfigMarket {
"Cancellation Penalty Percent"
)));
config.setCategoryPropertyOrder(AUCTION_BLACKLIST, new ArrayList<>(Arrays.asList(
"Enable Blacklist",
"Blacklisted Items",
"Blacklisted Mods",
"Blacklisted NBT Tags"
)));
config.setCategoryPropertyOrder(AUCTION_LOGGING, new ArrayList<>(Arrays.asList(
"Enable Auction Logging",
"Log Created",
@@ -21,6 +21,7 @@ import noppes.npcs.constants.EnumAuctionSort;
import noppes.npcs.constants.EnumAuctionStatus;
import noppes.npcs.constants.EnumClaimType;
import noppes.npcs.constants.EnumNotificationType;
import noppes.npcs.controllers.data.AuctionBlacklist;
import noppes.npcs.controllers.data.AuctionClaim;
import noppes.npcs.controllers.data.AuctionFilter;
import noppes.npcs.controllers.data.AuctionListing;
@@ -86,6 +87,7 @@ public class AuctionController implements IAuctionHandler {
public AuctionController() {
Instance = this;
AuctionBlacklist.reload();
load();
}
@@ -241,6 +243,11 @@ public class AuctionController implements IAuctionHandler {
return "Auction is disabled.";
}
// Check blacklist (with bypass for admins)
if (AuctionBlacklist.isBlacklistedForPlayer(item, player)) {
return "This item cannot be listed on the Auction House.";
}
// Validate minimum price
if (startingPrice < ConfigMarket.MinimumListingPrice) {
return "Starting price must be at least " + ConfigMarket.MinimumListingPrice + " " + ConfigMarket.CurrencyName + ".";
@@ -1414,4 +1421,18 @@ public class AuctionController implements IAuctionHandler {
AuctionListing listing = listings.get(listingId);
return listing != null && listing.isSeller(playerUUID);
}
/**
* Reload the item blacklist from config.
*/
public void reloadBlacklist() {
AuctionBlacklist.reload();
}
/**
* Check if an item is blacklisted.
*/
public boolean isItemBlacklisted(ItemStack item) {
return AuctionBlacklist.isBlacklisted(item);
}
}
@@ -0,0 +1,237 @@
package noppes.npcs.controllers.data;
import cpw.mods.fml.common.registry.GameRegistry;
import kamkeel.npcs.util.AttributeItemUtil;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.config.ConfigMarket;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
public class AuctionBlacklist {
private static Set<String> blacklistedItems = new HashSet<>();
private static Set<Pattern> wildcardPatterns = new HashSet<>();
private static Set<String> blacklistedMods = new HashSet<>();
private static Set<String> blacklistedNBTTags = new HashSet<>();
// Built-in bound item requirement keys (always blocked)
private static final String SOULBIND_KEY = "cnpc_soulbind";
private static final String PROFILE_SLOT_KEY = "cnpc_profile_slot";
// Bypass permission
private static final String BYPASS_PERMISSION = "customnpcs.auction.blacklist.bypass";
public static void reload() {
blacklistedItems.clear();
wildcardPatterns.clear();
blacklistedMods.clear();
blacklistedNBTTags.clear();
// Load blacklisted items
for (String item : ConfigMarket.BlacklistedItems) {
if (item == null || item.isEmpty()) continue;
item = item.toLowerCase().trim();
if (item.contains("*")) {
String regex = "^" + item.replace(".", "\\.").replace("*", ".*") + "$";
wildcardPatterns.add(Pattern.compile(regex));
} else {
blacklistedItems.add(item);
}
}
// Load blacklisted mods
for (String mod : ConfigMarket.BlacklistedMods) {
if (mod == null || mod.isEmpty()) continue;
blacklistedMods.add(mod.toLowerCase().trim());
}
// Load blacklisted NBT tags
for (String tag : ConfigMarket.BlacklistedNBTTags) {
if (tag == null || tag.isEmpty()) continue;
blacklistedNBTTags.add(tag.trim());
}
}
/**
* Check if player can bypass the blacklist (OP or has permission)
*/
public static boolean canBypass(EntityPlayer player) {
if (player == null) return false;
// Check OP status
if (player.canCommandSenderUseCommand(2, BYPASS_PERMISSION)) {
return true;
}
// Check custom permission
return CustomNpcsPermissions.hasCustomPermission(player, BYPASS_PERMISSION);
}
/**
* Check if item is blacklisted (without bypass check)
*/
public static boolean isBlacklisted(ItemStack item) {
if (!ConfigMarket.BlacklistEnabled) return false;
if (item == null || item.getItem() == null) return true;
// Check bound items (always blocked, even if blacklist is "disabled")
if (hasBoundRequirement(item)) {
return true;
}
// Get registry name
GameRegistry.UniqueIdentifier uid = GameRegistry.findUniqueIdentifierFor(item.getItem());
if (uid == null) return true;
String registryName = (uid.modId + ":" + uid.name).toLowerCase();
String modId = uid.modId.toLowerCase();
// Check exact item match
if (blacklistedItems.contains(registryName)) {
return true;
}
// Check wildcard patterns
for (Pattern pattern : wildcardPatterns) {
if (pattern.matcher(registryName).matches()) {
return true;
}
}
// Check mod blacklist
if (blacklistedMods.contains(modId)) {
return true;
}
// Check NBT tags
if (item.hasTagCompound() && !blacklistedNBTTags.isEmpty()) {
NBTTagCompound tag = item.getTagCompound();
for (String nbtKey : blacklistedNBTTags) {
if (tag.hasKey(nbtKey)) {
return true;
}
}
}
return false;
}
/**
* Check if item is blacklisted for a specific player (with bypass check)
*/
public static boolean isBlacklistedForPlayer(ItemStack item, EntityPlayer player) {
if (canBypass(player)) return false;
return isBlacklisted(item);
}
/**
* Get the registry name of an item
*/
public static String getRegistryName(ItemStack item) {
if (item == null || item.getItem() == null) return null;
GameRegistry.UniqueIdentifier uid = GameRegistry.findUniqueIdentifierFor(item.getItem());
if (uid == null) return null;
return uid.modId + ":" + uid.name;
}
// =========================================
// Bound Item Checking (RPGCore/Requirements)
// =========================================
/**
* Check if item has soulbind or profile slot requirement.
* Requirements are stored under: item.stackTagCompound/RPGCore/Requirements
*/
private static boolean hasBoundRequirement(ItemStack item) {
if (item == null || !item.hasTagCompound()) return false;
NBTTagCompound root = item.getTagCompound();
if (!root.hasKey(AttributeItemUtil.TAG_RPGCORE)) return false;
NBTTagCompound rpgCore = root.getCompoundTag(AttributeItemUtil.TAG_RPGCORE);
if (!rpgCore.hasKey(AttributeItemUtil.TAG_REQUIREMENTS)) return false;
NBTTagCompound requirements = rpgCore.getCompoundTag(AttributeItemUtil.TAG_REQUIREMENTS);
return requirements.hasKey(SOULBIND_KEY) || requirements.hasKey(PROFILE_SLOT_KEY);
}
// =========================================
// Runtime Blacklist Management
// =========================================
public static boolean addItem(String registryName) {
if (registryName == null || registryName.isEmpty()) return false;
registryName = registryName.toLowerCase().trim();
if (registryName.contains("*")) {
String regex = "^" + registryName.replace(".", "\\.").replace("*", ".*") + "$";
wildcardPatterns.add(Pattern.compile(regex));
} else {
blacklistedItems.add(registryName);
}
return true;
}
public static boolean removeItem(String registryName) {
if (registryName == null || registryName.isEmpty()) return false;
registryName = registryName.toLowerCase().trim();
if (registryName.contains("*")) {
String regex = "^" + registryName.replace(".", "\\.").replace("*", ".*") + "$";
return wildcardPatterns.removeIf(p -> p.pattern().equals(regex));
} else {
return blacklistedItems.remove(registryName);
}
}
public static boolean addMod(String modId) {
if (modId == null || modId.isEmpty()) return false;
return blacklistedMods.add(modId.toLowerCase().trim());
}
public static boolean removeMod(String modId) {
if (modId == null || modId.isEmpty()) return false;
return blacklistedMods.remove(modId.toLowerCase().trim());
}
public static boolean addNBTTag(String tag) {
if (tag == null || tag.isEmpty()) return false;
return blacklistedNBTTags.add(tag.trim());
}
public static boolean removeNBTTag(String tag) {
if (tag == null || tag.isEmpty()) return false;
return blacklistedNBTTags.remove(tag.trim());
}
// =========================================
// Getters for listing
// =========================================
public static List<String> getBlacklistedItems() {
List<String> result = new ArrayList<>(blacklistedItems);
for (Pattern p : wildcardPatterns) {
// Convert regex back to wildcard format
String pattern = p.pattern();
pattern = pattern.substring(1, pattern.length() - 1); // Remove ^ and $
pattern = pattern.replace("\\.", ".").replace(".*", "*");
result.add(pattern);
}
return result;
}
public static List<String> getBlacklistedMods() {
return new ArrayList<>(blacklistedMods);
}
public static List<String> getBlacklistedNBTTags() {
return new ArrayList<>(blacklistedNBTTags);
}
}