1.5 - Stable 1.19 Release

This commit is contained in:
NotAlexNoyle committed 2024-10-07 15:18:57 +00:00
1 parent e7c0f7c89b
commit 5d524a13da
25 files changed
+908 -951

No files matched your search

+5
View File
@@ -1,3 +1,8 @@
**1.5:**
- Create audience, global, and relative MiniPlaceholders in one new, simple API.
- Expand and format MiniPlaceholders within MiniPlaceholders.
- First 1.19 Stable Release.
**1.4.7:**
- Expand global and relational placeholders.
+93 -70
View File
@@ -52,30 +52,30 @@ At the moment, any config change requires a server restart to take effect.
### API Documentation:
**[void] trueOGMessage(Player player, String message)**
**[void] trueogMessage(Player player, String message)**
Send a message to the player with TrueOG formatting. Supports modern color codes and legacy Bukkit color codes (case-insensitive).
Sends a message to the specified player with TrueOG formatting. Supports both modern color codes and legacy Bukkit color codes (case-insensitive). Automatically expands MiniPlaceholders within the message.
Kotlin:
```kotlin
val targetPlayer = Bukkit.getPlayer("USERNAME")
UtilitiesOG.trueOGMessage(targetPlayer, "&6This is a &*message with <green>True&4OG <bold>formatting!")
UtilitiesOG.trueogMessage(targetPlayer, "&6This is a &*message with <green>True&4OG <bold>formatting!")
```
Java:
```java
Player targetPlayer = Bukkit.getPlayer("USERNAME");
UtilitiesOG.trueOGMessage(targetPlayer, "&6This is a &*message with <green>True&4OG <bold>formatting!");
UtilitiesOG.trueogMessage(targetPlayer, "&6This is a &*message with <green>True&4OG <bold>formatting!");
```
**[void] trueogMessage(UUID playerUUID, String message)**
Send a message to the player with TrueOG formatting in environments where the Bukkit API is not available. Supports modern color codes and legacy Bukkit color codes (case-insensitive).
Sends a message to a player identified by their UUID with TrueOG formatting. Useful when the Bukkit Player object is not available. Supports modern color codes and legacy Bukkit color codes (case-insensitive), and expands MiniPlaceholders within the message.
Kotlin:
```kotlin
val playerUUID = UUID.fromString("player_uuid")
UtilitiesOG.trueogMessage(playerUUID, "&6Hello there!")
UUID playerUUID = UUID.fromString("player_uuid");
UtilitiesOG.trueogMessage(playerUUID, "&6Hello there!");
```
Java:
@@ -84,115 +84,159 @@ UUID playerUUID = UUID.fromString("player_uuid");
UtilitiesOG.trueogMessage(playerUUID, "&6Hello there!");
```
**[TextComponent] trueOGExpandMiniPlaceholders(Player player, String input)**
**[TextComponent] trueogExpandMiniPlaceholders(String message)**
Expands MiniPlaceholders within a string for the given player, with support for color code processing via trueogColorize().
Expands MiniPlaceholders within a message string without any player context. Supports color code processing via TrueOG's formatting.
Kotlin:
```kotlin
val message = "Welcome to the server, everyone!"
val expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message)
```
Java:
```java
String message = "Welcome to the server, everyone!";
TextComponent expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message);
```
**[TextComponent] trueogExpandMiniPlaceholders(String message, Player player)**
Expands MiniPlaceholders within a message string using the provided player's context. Supports color code processing.
Kotlin:
```kotlin
val targetPlayer = Bukkit.getPlayer("SomePlayer")
val message = "Welcome back, <player_display_name>!"
val expandedMessage = UtilitiesOG.trueOGExpandMiniPlaceholders(targetPlayer, message)
UtilitiesOG.trueOGMessage(targetPlayer, expandedMessage)
val expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message, targetPlayer)
UtilitiesOG.trueogMessage(targetPlayer, expandedMessage)
```
Java:
```java
Player targetPlayer = Bukkit.getPlayer("SomePlayer");
String message = "Welcome back, <player_display_name>!";
TextComponent expandedMessage = UtilitiesOG.trueOGExpandMiniPlaceholders(targetPlayer, message);
UtilitiesOG.trueOGMessage(targetPlayer, expandedMessage);
TextComponent expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message, targetPlayer);
UtilitiesOG.trueogMessage(targetPlayer, expandedMessage);
```
**[TextComponent] trueogExpandMiniPlaceholders(UUID playerUUID, String input)**
**[TextComponent] trueogExpandMiniPlaceholders(String message, Player player, Player target)**
Expands MiniPlaceholders within a string for the given player, with support for color code processing via trueogColorize() in environments where the Bukkit API is not available.
Expands MiniPlaceholders within a message string using both the sender's and the target's player contexts, which is useful for relational placeholders. Supports color code processing.
Kotlin:
```kotlin
val player = Bukkit.getPlayer("Player")
val target = Bukkit.getPlayer("TargetPlayer")
val message = "<player_display_name> is sending a message to <target_display_name>"
val expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message, player, target)
UtilitiesOG.trueogMessage(player, expandedMessage)
```
Java:
```java
Player player = Bukkit.getPlayer("Player");
Player target = Bukkit.getPlayer("TargetPlayer");
String message = "<player_display_name> is sending a message to <target_display_name>";
TextComponent expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message, player, target);
UtilitiesOG.trueogMessage(player, expandedMessage);
```
**[TextComponent] trueogExpandMiniPlaceholders(String message, UUID playerUUID)**
Expands MiniPlaceholders within a message string using a player's UUID, useful when the Player object isn't available. Supports color code processing.
Kotlin:
```kotlin
val playerUUID = UUID.fromString("player_uuid")
val input = "Welcome back, <player_display_name>!"
val expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(playerUUID, input)
UtilitiesOG.trueOGMessage(playerUUID, expandedMessage)
val message = "Welcome back, <player_display_name>!"
val expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message, playerUUID)
UtilitiesOG.trueogMessage(playerUUID, expandedMessage)
```
Java:
```java
UUID playerUUID = UUID.fromString("player_uuid");
String input = "Welcome back, <player_display_name>!";
TextComponent expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(playerUUID, input);
UtilitiesOG.trueOGMessage(playerUUID, expandedMessage);
String message = "Welcome back, <player_display_name>!";
TextComponent expandedMessage = UtilitiesOG.trueogExpandMiniPlaceholders(message, playerUUID);
UtilitiesOG.trueogMessage(playerUUID, expandedMessage);
```
**[TextComponent] trueogColorize(String message)**
**[void] registerGlobalPlaceholder(String placeholderName, {String})**
Converts a message string into a formatted TextComponent using both legacy and modern color codes, along with MiniMessage processing.
Registers a global MiniPlaceholder that can be used anywhere in your messages. The valueSupplier provides the placeholder's value at runtime.
Kotlin:
```kotlin
val myMessage = UtilitiesOG.trueogColorize("&6This is a &*message with <green>True&4OG <bold>formatting!")
UtilitiesOG.registerGlobalPlaceholder("server_name") { "&aTrue&cOG &eNetwork" }
```
Java:
```java
TextComponent myMessage = UtilitiesOG.trueogColorize("&6This is a &*message with <green>True&4OG <bold>formatting!");
UtilitiesOG.registerGlobalPlaceholder("server_name", () -> "&aTrue&cOG &eNetwork");
```
**[void] trueOGRegisterMiniPlaceholder(String placeholderName, PlaceholderType placeholderType, String content)**
**[void] registerAudiencePlaceholder(String name, player -> {String})**
Creates and registers a MiniPlaceholder with the specified name and type. The content can include global MiniPlaceholders that will be expanded during registration. Placeholder Types include AUDIENCE, RELATIVE, and GLOBAL.
Registers an audience-specific MiniPlaceholder. The valueFunction uses the player's context to generate a dynamic value for the placeholder.
Kotlin:
```kotlin
val placeholderName = "example_placeholder"
val placeholderType = PlaceholderType.STRING
val content = "Hello, <player_name>!"
UtilitiesOG.trueOGRegisterMiniPlaceholder(placeholderName, placeholderType, content)
UtilitiesOG.registerAudiencePlaceholder("player_display_name") { player ->
val luckPerms = LuckPermsProvider.get()
val user = luckPerms.getUserManager().getUser(player.uniqueId)
val prefix = user?.cachedData?.metaData?.prefix ?: ""
"$prefix ${player.name}"
}
```
Java:
```java
String placeholderName = "example_placeholder";
PlaceholderType placeholderType = PlaceholderType.STRING;
String content = "Hello, <player_name>!";
UtilitiesOG.trueOGRegisterMiniPlaceholder(placeholderName, placeholderType, content);
UtilitiesOG.registerAudiencePlaceholder("player_display_name", player -> {
LuckPerms luckPerms = LuckPermsProvider.get();
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
String prefix = user != null ? user.getCachedData().getMetaData().getPrefix() : "";
return prefix + " " + player.getName();
});
```
**[void] trueOGUnregisterMiniPlaceholder(String placeholderName)**
**[void] registerRelationalPlaceholder(String name, player, target -> {String})**
Unregisters a previously registered MiniPlaceholder by its name.
Registers a relational MiniPlaceholder that depends on two players (e.g., viewer and target). The valueFunction provides a dynamic value based on both players' contexts.
Kotlin:
```kotlin
val placeholderName = "example_placeholder"
UtilitiesOG.trueOGUnregisterMiniPlaceholder(placeholderName)
UtilitiesOG.registerRelationalPlaceholder("distance_between") { player, target ->
val distance = player.location.distance(target.location)
"Distance: ${distance.toInt()} blocks"
}
```
Java:
```java
String placeholderName = "example_placeholder";
UtilitiesOG.trueOGUnregisterMiniPlaceholder(placeholderName);
UtilitiesOG.registerRelationalPlaceholder("distance_between", (player, target) -> {
double distance = player.getLocation().distance(target.getLocation());
return "Distance: " + (int) distance + " blocks";
});
```
**[boolean] isMiniPlaceholderRegistered(String placeholderName)**
**[void] logToConsole(Plugin plugin, String message)**
Checks if a MiniPlaceholder is already registered based on its name.
Logs a message to the server console with the prefix of the calling plugin. The message will have color codes and formatting stripped.
Kotlin:
```kotlin
val placeholderName = "example_placeholder"
val isRegistered = UtilitiesOG.isMiniPlaceholderRegistered(placeholderName)
UtilitiesOG.logToConsole(plugin, "&6This is a &*message with <green>color codes!")
```
Java:
```java
String placeholderName = "example_placeholder";
boolean isRegistered = UtilitiesOG.isMiniPlaceholderRegistered(placeholderName);
UtilitiesOG.logToConsole(plugin, "&6This is a &*message with <green>color codes!");
```
**[BukkitTask] runTaskAsynchronously(final Runnable run)**
Runs a task asynchronously as UtilitiesOG using the BukkitTask API.
Schedules a task to run asynchronously using the Bukkit scheduler under the UtilitiesOG plugin.
Kotlin:
```kotlin
@@ -206,25 +250,4 @@ Java:
BukkitTask asyncTask = UtilitiesOG.runTaskAsynchronously(() -> {
// Your async code here
});
```
**[void] logToConsole(Plugin plugin, String message)**
Logs a message directly to the server console with the prefix of the plugin that is using the API. The message will be stripped of any color codes or formatting.
Kotlin:
```kotlin
UtilitiesOG.logToConsole(plugin, "&6This is a &*message with <green>color codes!")
```
Java:
```java
UtilitiesOG.logToConsole(plugin, "&6This is a &*message with <green>color codes!");
```
## TODO:
- Global Placeholder Registration.
- Relative Placeholder Registration.
```
+1 -1
View File
@@ -11,7 +11,7 @@ java {
}
group = "net.trueog.utilities-og" // Declare bundle identifier.
version = "1.4.7" // Declare plugin version (will be in .jar).
version = "1.5" // Declare plugin version (will be in .jar).
val apiVersion = "1.19" // Declare minecraft server target version.
@@ -1,421 +0,0 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import com.sk89q.worldguard.protection.flags.StateFlag;
import me.barny1094875.utilitiesog.Listeners.DisableEntityCrammingListener;
import me.barny1094875.utilitiesog.Listeners.NoFlippyListener;
import me.barny1094875.utilitiesog.Listeners.TogglePhantomsListener;
import me.barny1094875.utilitiesog.commands.AboutCommand;
import me.barny1094875.utilitiesog.commands.BingCommand;
import me.barny1094875.utilitiesog.commands.ColorCodesCommand;
import me.barny1094875.utilitiesog.commands.PingCommand;
import me.barny1094875.utilitiesog.commands.RanksCommand;
import me.barny1094875.utilitiesog.commands.ToggleCrammingCommand;
import me.barny1094875.utilitiesog.commands.TogglePhantomsCommand;
import me.barny1094875.utilitiesog.internal.FlagRegistrationException;
import me.barny1094875.utilitiesog.internal.PlaceholderType;
import me.barny1094875.utilitiesog.modules.ChainArmorModule;
import me.barny1094875.utilitiesog.modules.MockBambooModule;
import me.barny1094875.utilitiesog.utils.PlaceholderUtils;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
// Declare main plugin class.
public final class UtilitiesOG extends JavaPlugin {
// Declare empty fields for use later.
private File file;
private static UtilitiesOG plugin;
private static FileConfiguration config;
private PlaceholderUtils playerDisplayNameMiniPlaceholder;
private static File phantomPreferencesFile;
private static YamlConfiguration phantomPreferences;
private static StateFlag FlippyFlag;
// Maintain a map of registered placeholders.
private static final Map<String, PlaceholderUtils> registeredPlaceholders = new HashMap<>();
// When the plugin is enabled, do this...
@Override
public void onEnable() {
// Populate the main class getter getPlugin().
plugin = this;
// Attempt to populate the file object with the config file.
this.file = new File(this.getDataFolder(), "config.yml");
// If the config file was not found, do this...
if (! this.file.exists()) {
// Create the config file in the filesystem using the one in the assembled plugin .jar.
this.saveDefaultConfig();
}
// Cast the config file from a File to a FileConfiguration.
config = this.getConfig();
// Attempt to populate the file object with the phantom toggle cache file.
phantomPreferencesFile = new File(this.getDataFolder(), "phantomDisabledUsers.yml");
try {
// If the phantom toggle cache file was not found, do this...
if (! phantomPreferencesFile.exists()) {
// Create the phantom toggle cache file in the filesystem using the one in the assembled plugin .jar.
phantomPreferencesFile.createNewFile();
}
}
// If there is a file IO error, do this...
catch (IOException error) {
// Log the problem with creating the phantom toggle cache file to the server console.
this.getLogger().severe("ERROR: Failed to create the phantom toggle cache file! " + error.getMessage());
}
// Cast the phantom toggle cache file from a File to a YamlConfiguration.
phantomPreferences = YamlConfiguration.loadConfiguration(phantomPreferencesFile);
// TrueOG Network Contributors: set up each feature below, using the config file to enable only that which is desirable by default.
// Be sure to label, using comments, which feature(s) each block is enabling.
// FEATURE: Enable crafting chain armor using chains.
// If the Chain Armor Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("ChainArmor")) {
// Enable the Chain Armor Module.
ChainArmorModule.Enable();
}
// FEATURE: Display information to the player about the syntax for bukkit's color codes.
// If the Color Codes Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("ColorCodes")) {
// If the Color Codes Module is enabled in the config file, do this...
this.getCommand("colorcodes").setExecutor(new ColorCodesCommand());
}
// FEATURE: Disable entity cramming server-wide. Entity cramming is when mobs pile up and cause damage to each other.
// WARNING: Make sure there is another plugin that establishes entity limits if this module is enabled. Otherwise the server will lag.
// If the Entity Cramming Toggle Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("DisableEntityCramming")) {
// Activate the Entity Cramming Toggle Listener.
getServer().getPluginManager().registerEvents(new DisableEntityCrammingListener(), this);
// Activate the Entity Cramming Toggle Command.
this.getCommand("togglecramming").setExecutor(new ToggleCrammingCommand());
}
// FEATURE: A custom, easy to use MiniPlaceholders API.
// If the built-in MiniPlaceholders Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("MiniPlaceholders")) {
trueogRegisterMiniPlaceholder("player_display_name", PlaceholderType.AUDIENCE, "<dark_purple><luckperms_prefix><player></dark_purple>");
}
// FEATURE: Pre-1.20 Mock Bamboo Wood. Makes Bamboo craft into Oak Planks called "Bamboo Wood".
// If the Bamboo Wood Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("MockBamboo")) {
// Enable the Bamboo Wood Module.
MockBambooModule.Enable();
}
// FEATURE: Prevent trap doors from being flipped in any WorldGuard regions with the "can-flippy" flag set to DENY.
// If the NoFlippy Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("NoFlippy")) {
// If WorldGuard is installed, do this...
if (getServer().getPluginManager().getPlugin("WorldGuard") != null) {
// Activate the NoFlippy Listener.
getServer().getPluginManager().registerEvents(new NoFlippyListener(), this);
}
// If WorldGuard is not installed, do this...
else {
// Log WorldGuard not being found to the server console.
this.getLogger().severe("WorldGuard is not installed! Disabling NoFlippy...");
}
}
// FEATURE: A /ping command that returns a player's real ping.
// FEATURE: A /bing command that replicates the functionality of the default /ping command.
// If the Ping Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("Ping")) {
// Enable the Ping command.
this.getCommand("ping").setExecutor(new PingCommand());
// Enable the Bing command.
this.getCommand("bing").setExecutor(new BingCommand());
}
// FEATURE: Display information to the player about the ranks available at the TrueOG Network Store (https://store.true-og.net/).
// If the Ranks Menu Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("RanksMenu")) {
// Activate the Ranks Command.
this.getCommand("ranks").setExecutor(new RanksCommand());
}
// FEATURE: Enable individual players to toggle phantom spawning on or off with the command /togglephantoms.
// If the Phantom Toggle Module is enabled in the config file, do this...
if (this.getConfig().getBoolean("TogglePhantoms")) {
// Activate the Phantom Toggle Listener.
getServer().getPluginManager().registerEvents(new TogglePhantomsListener(), this);
// Activate the Phantom Toggle Command.
this.getCommand("togglephantoms").setExecutor(new TogglePhantomsCommand());
}
// FEATURE: Display meta-information about Utilities-OG. Always enabled.
// Enable the root /utilities command to display information about the plugin to the player.
this.getCommand("utilities").setExecutor(new AboutCommand());
}
// After the server loads, do this...
@Override
public void onLoad() {
try {
// Register the Flag "can-flippy" with WorldGuard, and make the it retrievable.
FlippyFlag = NoFlippyListener.registerNoFlippyWorldGuardFlag(FlippyFlag);
}
// If the WorldGuard Flag registration failed, do this...
catch (FlagRegistrationException error) {
// Log the WorldGuard Flag registration error to the server console.
this.getLogger().severe("ERROR: Failed to register the can-flippy Flag with WorldGuard. " + error.getMessage());
}
}
// As the server un-loads, do this...
@Override
public void onDisable() {
// Unregister the MiniPlaceholderAPI if it was enabled.
disableMiniPlaceholderAPI();
}
// Unregister the placeholder.
private void disableMiniPlaceholderAPI() {
if (playerDisplayNameMiniPlaceholder != null) {
String placeholderName = playerDisplayNameMiniPlaceholder.getFullPlaceholderName();
trueogUnregisterMiniPlaceholder(placeholderName);
playerDisplayNameMiniPlaceholder = null;
}
}
// Getter for the config file.
public static FileConfiguration config() {
// Return the config file in FileConfiguration form.
return config;
}
// Getter for the FlippyFlag state.
public static StateFlag getFlippyFlag() {
// Return the FlippyFlag for WorldGuard.
return FlippyFlag;
}
// Getter for the phantom toggle cache file.
public static File getPhantomDisabledPlayersFile() {
// Return the phantom toggle cache file.
return phantomPreferencesFile;
}
// Getter for the phantom toggle cache file in YAML form.
public static YamlConfiguration getPhantomPreferences() {
// Return the phantom toggle cache file in YAML form.
return phantomPreferences;
}
// API for sending TrueOG Player messages. Supports modern color codes, and legacy Bukkit color codes (case INsensitive).
public static void trueogMessage(Player player, String message) {
// Forward the message to the server.
TextUtils.utilitiesOGMessage(player, message);
}
// API for TrueOG MiniPlaceholderAPI expansion (with color code processing from trueOGColorize).
public static TextComponent trueogExpandMiniPlaceholders(Player player, String input) {
// Expand all the MiniPlaceholders in a given String.
return TextUtils.expandMiniPlaceholders(input, player, null);
}
// Variant of trueOGMessage for use cases where the Bukkit API is not available.
public static void trueogMessage(UUID playerUUID, String message) {
// Forward the message to the server.
TextUtils.utilitiesOGMessage(Bukkit.getPlayer(playerUUID), message);
}
// Variant of the TrueOG MiniPlaceholder API for use cases where the Bukkit API is not available.
public static TextComponent trueogExpandMiniPlaceholders(UUID playerUUID, String input) {
// Expand all the MiniPlaceholders in a given String.
return TextUtils.expandMiniPlaceholders(input, Bukkit.getPlayer(playerUUID), null);
}
// API for the TrueOG text colorizer.
public static TextComponent trueogColorize(String message) {
// Convert the String's legacy color codes to modern ones.
String processedMessage = TextUtils.processColorCodes(message);
// Use MiniMessage to parse the modern colors in the String and convert it to a Component.
Component component = MiniMessage.miniMessage().deserialize(processedMessage);
// If the result is a TextComponent, do this...
if (component instanceof TextComponent) {
// Cast and send off.
return (TextComponent) component;
}
// If the result is not a TextComponent, do this...
else {
// Convert the Component to a TextComponent.
return Component.text().append(component).build();
}
}
// API for easy creation and registration of a MiniPlaceholder.
public static void trueogRegisterMiniPlaceholder(String placeholderName, PlaceholderType placeholderType, String content) {
int lastIndex = placeholderName.lastIndexOf('_');
String placeholderPrefix = "";
String placeholderSuffix = "";
if (lastIndex != -1) {
// Split the placeholder name into its prefix and suffix.
placeholderPrefix = placeholderName.substring(0, lastIndex);
placeholderSuffix = placeholderName.substring(lastIndex + 1);
}
// Register the placeholder with MiniPlaceholders
PlaceholderUtils placeholderUtils = new PlaceholderUtils(placeholderPrefix, placeholderSuffix, placeholderType, TextUtils.expandMiniPlaceholders(content, null, null));
// Register the placeholder and store it in the map.
placeholderUtils.register();
registeredPlaceholders.put(placeholderName, placeholderUtils);
}
// API to unregister a specific MiniPlaceholder by its name.
public static void trueogUnregisterMiniPlaceholder(String placeholderName) {
PlaceholderUtils placeholder = registeredPlaceholders.remove(placeholderName);
if (placeholder != null) {
placeholder.unregister();
}
else {
TextUtils.logToConsole("TrueOG MiniPlaceholdersAPI: Placeholder " + placeholderName + " not found.");
}
}
// API to check if a MiniPlaceholder is already registered based on its name.
public static boolean isMiniPlaceholderRegistered(String placeholderName) {
// Check if the placeholder is in the registeredPlaceholders map.
return registeredPlaceholders.containsKey(placeholderName);
}
// API to log a message to the console without any formatting.
public static void logToConsole(Plugin plugin, String message) {
// Send an unformatted console message with the plugin's prefix which is using the API.
Bukkit.getLogger().info("[" + plugin.getName() + "]" + " " + TextUtils.stripColors(message));
}
// API for getting the Utilities-OG instance.
public static UtilitiesOG getPlugin() {
// Return the current Utilities-OG instance.
return plugin;
}
// API for basic async tasks using the BukkitTask API.
public static BukkitTask runTaskAsynchronously(final Runnable run) {
// Schedule processes.
return getPlugin().getServer().getScheduler().runTaskAsynchronously(getPlugin(), run);
}
}
@@ -1,124 +0,0 @@
package me.barny1094875.utilitiesog.internal;
import java.util.function.Function;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.Node;
import net.luckperms.api.node.types.PrefixNode;
public enum PlaceholderType {
AUDIENCE(player -> {
// The placeholder logic will be provided externally.
return Tag.inserting(null);
}),
/*GLOBAL(player -> {
return Tag.inserting(null);
}),
RELATIVE(player -> {
return Tag.inserting(null);
})*/;
private final Function<Player, Tag> placeholderFunction;
PlaceholderType(Function<Player, Tag> placeholderFunction) {
this.placeholderFunction = placeholderFunction;
}
public Function<Player, Tag> getPlaceholderFunction() {
return placeholderFunction;
}
// Creates a placeholder function using the provided template.
public Function<Player, Tag> createPlaceholderFunction(TextComponent template) {
return player -> {
// Get the LuckPerms API instance.
LuckPerms luckPerms = LuckPermsProvider.get();
// Get the user's LuckPerms User object.
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
// Log the missing User to the console.
UtilitiesOG.getPlugin().getLogger().info("ERROR: MiniPlaceholder processing error. Player: " + player.getName() + "has no User object in LuckPerms!");
// Fallback to no formatting if the LuckPerms User cannot be found.
return Tag.inserting(Component.text(player.getName()));
}
// Get the player's primary group.
String primaryGroup = user.getPrimaryGroup();
// Fetch the LuckPerms group.
Group group = luckPerms.getGroupManager().getGroup(primaryGroup);
if (group == null) {
// Log the missing Group to the console.
UtilitiesOG.getPlugin().getLogger().info("ERROR: MiniPlaceholder processing error. User: " + player.getName() + "has no Group assignment in LuckPerms!");
// Fallback to no formatting if the LuckPerms User's Group cannot be found.
return Tag.inserting(Component.text(player.getName()));
}
// Find the prefix node within the group.
String prefix = null;
for (Node node : group.getNodes()) {
if (node instanceof PrefixNode) {
prefix = ((PrefixNode) node).getMetaValue();
break;
}
}
// If no prefix is found, default to using just the player's name.
if (prefix == null) {
return Tag.inserting(Component.text(player.getName()));
}
// Extract the color code from the prefix (after the "]").
String colorCode = prefix.replaceAll(".*\\](.*)", "$1");
// Use TextUtils to process the color codes in the player's name.
String coloredPlayerName = TextUtils.processColorCodes(colorCode + " " + player.getName());
// Replace <player> in the template with the colored player's name.
String formattedString = template.content().replace("<player>", coloredPlayerName);
// Convert the formatted string to an Adventure component using UtilitiesOG.
Component formattedComponent = UtilitiesOG.trueogExpandMiniPlaceholders(player, formattedString);
// Return the formatted Tag.
return Tag.inserting(formattedComponent);
};
}
}
@@ -1,76 +0,0 @@
package me.barny1094875.utilitiesog.utils;
import java.util.function.Function;
import org.bukkit.entity.Player;
import io.github.miniplaceholders.api.Expansion;
import me.barny1094875.utilitiesog.internal.PlaceholderType;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.tag.Tag;
public class PlaceholderUtils {
private final String miniPlaceholderPrefix;
private final String miniPlaceholderSuffix;
private final Function<Player, Tag> placeholderFunction;
private Expansion expansion;
public PlaceholderUtils(String miniPlaceholderPrefix, String miniPlaceholderSuffix, PlaceholderType placeholderType, TextComponent content) {
if (miniPlaceholderPrefix == null || miniPlaceholderSuffix == null) {
throw new IllegalArgumentException("[Utilities-OG] MiniPlaceholderAPI ERROR: Both the prefix and suffix parameters must be specified!");
}
this.miniPlaceholderPrefix = miniPlaceholderPrefix;
this.miniPlaceholderSuffix = miniPlaceholderSuffix;
this.placeholderFunction = placeholderType.createPlaceholderFunction(content);
}
public void register() {
if (expansion == null) {
expansion = Expansion.builder(miniPlaceholderPrefix).filter(Player.class)
.audiencePlaceholder(miniPlaceholderSuffix, (audience, ctx, queue) -> {
Player player = (Player) audience;
return placeholderFunction.apply(player);
}).build();
expansion.register();
String placeholder = "<" + miniPlaceholderPrefix + "_" + miniPlaceholderSuffix + ">";
TextUtils.logToConsole("TrueOG MiniPlaceholdersAPI expansion " + placeholder + " registered successfully.");
}
}
public void unregister() {
if (expansion != null) {
expansion.unregister();
// Simplified logging method to log the unregistration.
String placeholder = "<" + getFullPlaceholderName() + ">";
TextUtils.logToConsole("TrueOG MiniPlaceholdersAPI expansion " + placeholder + " unregistered successfully.");
expansion = null;
}
}
public String getFullPlaceholderName() {
return miniPlaceholderPrefix + "_" + miniPlaceholderSuffix;
}
}
@@ -1,216 +0,0 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.utils;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import io.github.miniplaceholders.api.MiniPlaceholders;
import me.barny1094875.utilitiesog.internal.ColorCodeMap;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
public class TextUtils {
// Regular expressions to match color codes starting with § or & in Strings.
private static final Pattern LEGACY_COLOR_PATTERN = Pattern.compile("(?i)[§&][0-9A-FK-OR]");
private static final Pattern MINIMESSAGE_TAG_PATTERN = Pattern.compile("<[^>]*>");
// Sends a formatted message to the player.
public static void utilitiesOGMessage(Player player, String message) {
// First, process the message for color codes.
String colorProcessedMessage = processColorCodes(message);
// Then, expand the MiniPlaceholders.
TextComponent finalMessage = expandMiniPlaceholders(colorProcessedMessage, player, null);
// Send the final message to the player.
player.sendMessage(finalMessage);
}
// Processes color codes in the message, converting Bukkit color codes to MiniMessage codes.
public static String processColorCodes(String message) {
// Keeps track of the ampersand count in the loop.
int count = 0;
// Count the number of ampersand characters to determine how many there are for lowercase conversion.
for (char c : message.toCharArray()) {
// If the character is an ampersand, do this...
if (c == '&') {
// Increase the ampersand count by 1.
count++;
}
}
// Keeps track of the positions of '&' characters in the message String.
int[] positions = new int[count];
// Keep track of the position of the metaphorical cursor in the message String.
int index = 0;
// Iterate through the message String to find the positions of '&' characters for lowercase conversion.
for (int i = 0; i < message.length(); i++) {
// If the character is an ampersand, do this...
if (message.charAt(i) == '&') {
// If the character directly after the ampersand is a valid uppercase Bukkit color code, do this...
if (isUpperBukkitCode(message.charAt(i + 1))) {
// Replace the valid uppercase Bukkit color code with the equivalent lowercase one.
message = replaceAtIndex(message, (i + 1), Character.toString(Character.toLowerCase(message.charAt(i + 1))));
}
try {
// Convert the newly uniform legacy Bukkit color codes into modern MiniMessage color / formatting codes.
message = replaceAtIndex(message, (i + 1), ColorCodeMap.toMiniMessage(message.charAt(i + 1)));
// Delete the leftover ampersand.
message = replaceAtIndex(message, i, "");
}
catch (NullPointerException error) {
// Do nothing, ampersand is intended to be in the message, since it's not a valid color code.
}
// Move the metaphorical cursor forward by one.
positions[index++] = i;
}
}
// Return the processed message with modern color codes.
return message;
}
// Unified function to expand global, audience, and relational MiniPlaceholders.
public static TextComponent expandMiniPlaceholders(String message, Player mainPlayer, Player relationalPlayer) {
// Start with global placeholders (these will always be included).
TagResolver globalPlaceholders = MiniPlaceholders.getGlobalPlaceholders();
TagResolver resolver = globalPlaceholders;
// If a main player is provided, add audience placeholders.
if (mainPlayer != null) {
TagResolver audiencePlaceholders = MiniPlaceholders.getAudiencePlaceholders(mainPlayer);
resolver = TagResolver.builder()
.resolver(resolver) // Add global placeholders.
.resolver(audiencePlaceholders) // Add player-specific placeholders.
.build();
}
// If a relational player is provided, add relational placeholders.
if (mainPlayer != null && relationalPlayer != null) {
TagResolver relationalPlaceholders = MiniPlaceholders.getRelationalPlaceholders(mainPlayer, relationalPlayer);
resolver = TagResolver.builder()
.resolver(resolver) // Include global and audience placeholders.
.resolver(relationalPlaceholders) // Add relational placeholders.
.build();
}
// Process color codes and formatting.
message = processColorCodes(message);
// Replace the placeholders in the message.
Component expandedMessage = MiniMessage.miniMessage().deserialize(message, resolver);
// Return the expanded message as a TextComponent.
return (TextComponent) expandedMessage;
}
// Log a Component message to the console, stripping colors.
public static void logToConsole(String message) {
Bukkit.getLogger().info(message);
}
// Strips color codes and MiniMessage tags from a String.
public static String stripColors(String input) {
if (input == null) return null;
// Remove MiniMessage tags
String stripped = MINIMESSAGE_TAG_PATTERN.matcher(input).replaceAll("");
// Remove legacy color codes
stripped = LEGACY_COLOR_PATTERN.matcher(stripped).replaceAll("");
return stripped;
}
// Detects if a Bukkit color code is uppercase.
private static boolean isUpperBukkitCode(char input) {
// An array of all potential uppercase Bukkit color code characters.
char[] bukkitColorCodes = {'A', 'B', 'C', 'D', 'E', 'F', 'K', 'L', 'M', 'N', 'O', 'R'};
// Keeps track of found uppercase Bukkit color codes.
boolean match = false;
// Loop through each character in the array.
for (char c : bukkitColorCodes) {
// Check if the current character in the array is equal to the input character.
if (c == input) {
// A match was found.
match = true;
}
}
// Return whether or not the character is an uppercase Bukkit color code.
return match;
}
// Replaces a character in a String at a given index with a new String.
private static String replaceAtIndex(String original, int index, String newString) {
// Check if the index is valid.
if (index >= 0 && index < original.length()) {
// Create a new string with the replacement.
return original.substring(0, index) + newString + original.substring(index + 1);
}
// If the index is invalid, return the original string. Soft error.
return original;
}
// Sends an error message to the player if they don't have permission to run a given command.
public static void permissionsErrorMessage(Player player, String command, String permission) {
// Send a formatted error message using the TrueOG Message API.
utilitiesOGMessage(player, ("&cERROR: You do not have permission to run the /" + command + " command! &6Required permission: &e" + permission + "&6."));
}
// Sends an error message to the console if the command which was run is only applicable to players.
public static void consoleUseErrorMessage(CommandSender sender, String command, String permission) {
// Send an unformatted error message directly to the console.
sender.sendMessage(("ERROR: The server console cannot execute the command: " + command + "! To run it in-game, ensure you have the permission: " + permission + "."));
}
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.Listeners;
package net.trueog.utilitiesog.Listeners;
// Import libraries.
import org.bukkit.event.EventHandler;
@@ -8,8 +8,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
// Import required libraries.
import me.barny1094875.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.UtilitiesOG;
// Declare the EntityCrammingToggle Module with Bukkit Listeners.
public class DisableEntityCrammingListener implements Listener {
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.Listeners;
package net.trueog.utilitiesog.Listeners;
// Import libraries.
import org.bukkit.block.Block;
@@ -21,8 +21,8 @@ import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.internal.FlagRegistrationException;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.internal.FlagRegistrationException;
// Declare the NoFlippy Module with Bukkit Listeners.
public class NoFlippyListener implements Listener {
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.Listeners;
package net.trueog.utilitiesog.Listeners;
// Import libraries.
import org.bukkit.Bukkit;
@@ -11,7 +11,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import me.barny1094875.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.UtilitiesOG;
// Declare the DisablePhantomSpawns Module with Bukkit Listeners.
public class TogglePhantomsListener implements Listener {
@@ -0,0 +1,369 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package net.trueog.utilitiesog;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import com.sk89q.worldguard.protection.flags.StateFlag;
import net.kyori.adventure.text.TextComponent;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.Node;
import net.luckperms.api.node.types.PrefixNode;
import net.trueog.utilitiesog.Listeners.DisableEntityCrammingListener;
import net.trueog.utilitiesog.Listeners.NoFlippyListener;
import net.trueog.utilitiesog.Listeners.TogglePhantomsListener;
import net.trueog.utilitiesog.commands.AboutCommand;
import net.trueog.utilitiesog.commands.BingCommand;
import net.trueog.utilitiesog.commands.ColorCodesCommand;
import net.trueog.utilitiesog.commands.PingCommand;
import net.trueog.utilitiesog.commands.RanksCommand;
import net.trueog.utilitiesog.commands.ToggleCrammingCommand;
import net.trueog.utilitiesog.commands.TogglePhantomsCommand;
import net.trueog.utilitiesog.internal.FlagRegistrationException;
import net.trueog.utilitiesog.modules.ChainArmorModule;
import net.trueog.utilitiesog.modules.MockBambooModule;
import net.trueog.utilitiesog.utils.PlaceholderUtils;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare main plugin class.
public final class UtilitiesOG extends JavaPlugin {
private File file;
private static UtilitiesOG plugin;
private static FileConfiguration config;
private static File phantomPreferencesFile;
private static YamlConfiguration phantomPreferences;
private static StateFlag FlippyFlag;
@Override
public void onEnable() {
plugin = this;
this.file = new File(this.getDataFolder(), "config.yml");
if (! this.file.exists()) {
this.saveDefaultConfig();
}
config = this.getConfig();
phantomPreferencesFile = new File(this.getDataFolder(), "phantomDisabledUsers.yml");
try {
if (! phantomPreferencesFile.exists()) {
phantomPreferencesFile.createNewFile();
}
}
catch (IOException error) {
this.getLogger().severe("ERROR: Failed to create the phantom toggle cache file! " + error.getMessage());
}
phantomPreferences = YamlConfiguration.loadConfiguration(phantomPreferencesFile);
if (this.getConfig().getBoolean("ChainArmor")) {
ChainArmorModule.Enable();
}
if (this.getConfig().getBoolean("ColorCodes")) {
this.getCommand("colorcodes").setExecutor(new ColorCodesCommand());
}
if (this.getConfig().getBoolean("DisableEntityCramming")) {
getServer().getPluginManager().registerEvents(new DisableEntityCrammingListener(), this);
this.getCommand("togglecramming").setExecutor(new ToggleCrammingCommand());
}
if (this.getConfig().getBoolean("MiniPlaceholders")) {
// Registering a global MiniPlaceholder.
registerGlobalPlaceholder("servers_name", () -> "&aTrue&cOG &eNetwork");
// Registering an Audience MiniPlaceholder.
registerAudiencePlaceholder("player_display_name", player -> {
LuckPerms luckPerms = LuckPermsProvider.get();
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
getPlugin().getLogger().info("ERROR: MiniPlaceholder processing error. Player: " + player.getName() + " has no User object in LuckPerms!");
return player.getName();
}
String primaryGroup = user.getPrimaryGroup();
Group group = luckPerms.getGroupManager().getGroup(primaryGroup);
if (group == null) {
getPlugin().getLogger().info("ERROR: MiniPlaceholder processing error. User: " + player.getName() + " has no Group assignment in LuckPerms!");
return player.getName();
}
String prefix = null;
for (Node node : group.getNodes()) {
if (node instanceof PrefixNode) {
prefix = ((PrefixNode) node).getMetaValue();
break;
}
}
if (prefix == null) {
return player.getName();
}
String colorCode = prefix.replaceAll(".*\\](.*)", "$1");
return "<luckperms_prefix>" + colorCode + " " + player.getName();
});
// Build and register all expansions after adding MiniPlaceholders.
PlaceholderUtils.buildAndRegisterExpansions();
}
if (this.getConfig().getBoolean("MockBamboo")) {
MockBambooModule.Enable();
}
if (this.getConfig().getBoolean("NoFlippy")) {
if (getServer().getPluginManager().getPlugin("WorldGuard") != null) {
getServer().getPluginManager().registerEvents(new NoFlippyListener(), this);
}
else {
this.getLogger().severe("WorldGuard is not installed! Disabling NoFlippy...");
}
}
if (this.getConfig().getBoolean("Ping")) {
this.getCommand("ping").setExecutor(new PingCommand());
this.getCommand("bing").setExecutor(new BingCommand());
}
if (this.getConfig().getBoolean("RanksMenu")) {
this.getCommand("ranks").setExecutor(new RanksCommand());
}
if (this.getConfig().getBoolean("TogglePhantoms")) {
getServer().getPluginManager().registerEvents(new TogglePhantomsListener(), this);
this.getCommand("togglephantoms").setExecutor(new TogglePhantomsCommand());
}
this.getCommand("utilities").setExecutor(new AboutCommand());
}
@Override
public void onLoad() {
try {
FlippyFlag = NoFlippyListener.registerNoFlippyWorldGuardFlag(FlippyFlag);
}
catch (FlagRegistrationException error) {
this.getLogger().severe("ERROR: Failed to register the can-flippy Flag with WorldGuard. " + error.getMessage());
}
}
@Override
public void onDisable() {
PlaceholderUtils.unregisterAll();
}
public static FileConfiguration config() {
return config;
}
public static StateFlag getFlippyFlag() {
return FlippyFlag;
}
public static File getPhantomDisabledPlayersFile() {
return phantomPreferencesFile;
}
public static YamlConfiguration getPhantomPreferences() {
return phantomPreferences;
}
// Unified method for sending a message to a player with placeholders processed.
public static void trueogMessage(Player player, String message) {
TextComponent finalMessage = TextUtils.expandTextWithPlaceholders(message, player);
player.sendMessage(finalMessage);
}
// Handle messages to offline players (based on UUID).
public static void trueogMessage(UUID playerUUID, String message) {
Player player = Bukkit.getPlayer(playerUUID);
if (player != null) {
trueogMessage(player, message);
}
else {
logToConsole(getPlugin(), "Player with UUID " + playerUUID + " is not online.");
}
}
public static TextComponent trueogExpandMiniPlaceholders(String message) {
return TextUtils.expandTextWithPlaceholders(message);
}
public static TextComponent trueogExpandMiniPlaceholders(String message, Player player) {
return TextUtils.expandTextWithPlaceholders(message, player);
}
public static TextComponent trueogExpandMiniPlaceholders(String message, Player player, Player target) {
return TextUtils.expandTextWithPlaceholders(message, player, target);
}
// Variation for when Bukkit API is unavailable.
public static TextComponent trueogExpandMiniPlaceholders(String message, UUID playerUUID) {
Player player = Bukkit.getPlayer(playerUUID);
if (player != null) {
return TextUtils.expandTextWithPlaceholders(message, player);
}
else {
logToConsole(getPlugin(), "Player with UUID " + playerUUID + " is not online.");
return TextUtils.expandTextWithPlaceholders(message);
}
}
public static void registerGlobalPlaceholder(String name, Supplier<String> valueSupplier) {
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
placeholder.setGlobalPlaceholder(valueSupplier);
});
}
public static void registerAudiencePlaceholder(String name, Function<Player, String> valueFunction) {
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
placeholder.setAudiencePlaceholder(valueFunction);
});
}
public static void registerRelationalPlaceholder(String name, BiFunction<Player, Player, String> valueFunction) {
PlaceholderUtils.trueogRegisterMiniPlaceholder(name, placeholder -> {
placeholder.setRelationalPlaceholder(valueFunction);
});
}
public static void logToConsole(Plugin plugin, String message) {
Bukkit.getLogger().info("[" + plugin.getName() + "] " + TextUtils.stripColors(message));
}
public static UtilitiesOG getPlugin() {
return plugin;
}
public static BukkitTask runTaskAsynchronously(final Runnable run) {
return getPlugin().getServer().getScheduler().runTaskAsynchronously(getPlugin(), run);
}
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
// Import libraries.
import org.bukkit.command.Command;
@@ -8,8 +8,8 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare the About Module with Bukkit Commands.
public class AboutCommand implements CommandExecutor {
@@ -47,7 +47,7 @@ public class AboutCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), aboutPermission);
TextUtils.logToConsole(cmd.getName() + " " + aboutPermission);
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
// Import libraries.
import org.bukkit.command.Command;
@@ -8,8 +8,8 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare the /bing command in the Ping Module with Bukkit Commands.
public class BingCommand implements CommandExecutor {
@@ -47,7 +47,7 @@ public class BingCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), pingPermission);
TextUtils.logToConsole(cmd.getName() + " " + pingPermission);
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
// Import libraries.
import org.bukkit.command.Command;
@@ -8,8 +8,8 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare the ColorCodes Module with Bukkit Commands.
public class ColorCodesCommand implements CommandExecutor {
@@ -69,7 +69,7 @@ public class ColorCodesCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), colorCodesPermission);
TextUtils.logToConsole(cmd.getName() + " " + colorCodesPermission);
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
// Import libraries.
import org.bukkit.Bukkit;
@@ -9,8 +9,8 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare the /ping command in the Ping Module with Bukkit Commands.
public class PingCommand implements CommandExecutor {
@@ -82,7 +82,7 @@ public class PingCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), pingPermission);
TextUtils.logToConsole(cmd.getName() + " " + pingPermission);
}
@@ -1,17 +1,17 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare the Ranks Module with Bukkit Commands.
public class RanksCommand implements CommandExecutor {
@@ -125,7 +125,7 @@ public class RanksCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), ranksPermission);
TextUtils.logToConsole(cmd.getName() + " " + ranksPermission);
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
// Import libraries.
import org.bukkit.command.Command;
@@ -9,8 +9,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.utils.TextUtils;
// Declare the /togglecramming command in the DisableEntityCramming Module with Bukkit Commands.
public class ToggleCrammingCommand implements CommandExecutor {
@@ -53,7 +53,7 @@ public class ToggleCrammingCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), toggleCrammingPermission);
TextUtils.logToConsole(cmd.getName() + " " + toggleCrammingPermission);
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.commands;
package net.trueog.utilitiesog.commands;
// Import libraries.
import java.io.IOException;
@@ -11,8 +11,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import me.barny1094875.utilitiesog.UtilitiesOG;
import me.barny1094875.utilitiesog.utils.TextUtils;
import net.trueog.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.utils.TextUtils;
//Declare the /togglephantoms command in the Ping Module with Bukkit Commands.
public class TogglePhantomsCommand implements CommandExecutor {
@@ -84,7 +84,7 @@ public class TogglePhantomsCommand implements CommandExecutor {
else {
// Send a detailed error message to the server console.
TextUtils.consoleUseErrorMessage(sender, cmd.getName(), togglePhantomsPermission);
TextUtils.logToConsole(cmd.getName() + " " + togglePhantomsPermission);
}
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.internal;
package net.trueog.utilitiesog.internal;
// Import libraries.
import java.util.HashMap;
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.internal;
package net.trueog.utilitiesog.internal;
// Declare a custom exception for the case where a WorldGuard Flag fails to register for internal use by Utilities-OG.
public class FlagRegistrationException extends Exception {
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.modules;
package net.trueog.utilitiesog.modules;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -8,8 +8,7 @@ import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
// Import libraries.
import me.barny1094875.utilitiesog.UtilitiesOG;
import net.trueog.utilitiesog.UtilitiesOG;
// Declare the Chain Armor Module.
public class ChainArmorModule {
@@ -1,6 +1,6 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package me.barny1094875.utilitiesog.modules;
package net.trueog.utilitiesog.modules;
// Import libraries.
import org.bukkit.Bukkit;
@@ -10,9 +10,9 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import me.barny1094875.utilitiesog.UtilitiesOG;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.trueog.utilitiesog.UtilitiesOG;
// Declare the Mock Bamboo Wood Module.
public class MockBambooModule {
@@ -0,0 +1,187 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package net.trueog.utilitiesog.utils;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.bukkit.entity.Player;
import io.github.miniplaceholders.api.Expansion;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.tag.Tag;
public class PlaceholderUtils {
// Map to store Expansion Builders per prefix.
private static final Map<String, Expansion.Builder> expansionBuilders = new HashMap<>();
// Map to store registered expansions.
private static final Map<String, Expansion> expansions = new HashMap<>();
private final String miniPlaceholderPrefix;
private final String miniPlaceholderSuffix;
// MiniPlaceholder functions.
private Supplier<String> globalPlaceholder;
private Function<Player, String> audiencePlaceholder;
private BiFunction<Player, Player, String> relationalPlaceholder;
// Constructor for prefix and suffix.
public PlaceholderUtils(String placeholderPrefix, String placeholderSuffix) {
this.miniPlaceholderPrefix = placeholderPrefix;
this.miniPlaceholderSuffix = placeholderSuffix;
}
// Setters for global, audience, and relational MiniPlaceholders.
public PlaceholderUtils setGlobalPlaceholder(Supplier<String> placeholder) {
this.globalPlaceholder = placeholder;
return this;
}
public PlaceholderUtils setAudiencePlaceholder(Function<Player, String> placeholder) {
this.audiencePlaceholder = placeholder;
return this;
}
public PlaceholderUtils setRelationalPlaceholder(BiFunction<Player, Player, String> placeholder) {
this.relationalPlaceholder = placeholder;
return this;
}
// Register the MiniPlaceholder with recursive expansion.
public void register() {
Expansion.Builder builder = expansionBuilders.get(miniPlaceholderPrefix);
if (builder == null) {
builder = Expansion.builder(miniPlaceholderPrefix);
expansionBuilders.put(miniPlaceholderPrefix, builder);
}
// Global MiniPlaceholder with recursive expansion.
if (globalPlaceholder != null) {
builder.globalPlaceholder(miniPlaceholderSuffix, (queue, ctx) -> {
TextComponent result = TextUtils.expandTextWithPlaceholders(globalPlaceholder.get());
return Tag.inserting(result);
});
}
// Audience MiniPlaceholder with recursive expansion.
if (audiencePlaceholder != null) {
builder.audiencePlaceholder(miniPlaceholderSuffix, (audience, queue, ctx) -> {
if (audience instanceof Player player) {
TextComponent result = TextUtils.expandTextWithPlaceholders(audiencePlaceholder.apply(player), player);
return Tag.inserting(result);
}
return Tag.inserting(Component.empty());
});
}
// Relational MiniPlaceholder with recursive expansion.
if (relationalPlaceholder != null) {
builder.relationalPlaceholder(miniPlaceholderSuffix, (audience, otherAudience, queue, ctx) -> {
if (audience instanceof Player player && otherAudience instanceof Player targetPlayer) {
TextComponent result = TextUtils.expandTextWithPlaceholders(relationalPlaceholder.apply(player, targetPlayer), player, targetPlayer);
return Tag.inserting(result);
}
return Tag.inserting(Component.empty());
});
}
}
// Build and register all expansions.
public static void buildAndRegisterExpansions() {
for (Map.Entry<String, Expansion.Builder> entry : expansionBuilders.entrySet()) {
Expansion expansion = entry.getValue().build();
expansion.register();
expansions.put(entry.getKey(), expansion);
}
// Clean up the builders after they're done being used.
expansionBuilders.clear();
}
// API for registering the MiniPlaceholder (global, audience, or relational).
public static void trueogRegisterMiniPlaceholder(String placeholderName, Consumer<PlaceholderUtils> placeholderConfigurator) {
// Split placeholder name into prefix and suffix using the last underscore.
int lastIndex = placeholderName.lastIndexOf('_');
if (lastIndex == -1) {
throw new IllegalArgumentException("Placeholder name must contain an underscore separating prefix and suffix.");
}
String placeholderPrefix = placeholderName.substring(0, lastIndex);
String placeholderSuffix = placeholderName.substring(lastIndex + 1);
// Create a new PlaceholderUtils instance.
PlaceholderUtils placeholderUtils = new PlaceholderUtils(placeholderPrefix, placeholderSuffix);
// Apply the provided configuration (lambda).
placeholderConfigurator.accept(placeholderUtils);
// Register the MiniPlaceholder and adds it to the builder.
placeholderUtils.register();
}
public static void unregisterAll() {
for (Expansion expansion : expansions.values()) {
expansion.unregister();
}
expansions.clear();
}
}
@@ -0,0 +1,212 @@
// This is free and unencumbered software released into the public domain.
// Authors: christianniehaus, NotAlexNoyle.
package net.trueog.utilitiesog.utils;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import io.github.miniplaceholders.api.MiniPlaceholders;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.trueog.utilitiesog.internal.ColorCodeMap;
public class TextUtils {
// Regular expressions to match color codes starting with § or & in Strings.
private static final Pattern LEGACY_COLOR_PATTERN = Pattern.compile("(?i)[§&][0-9A-FK-OR]");
private static final Pattern MINIMESSAGE_TAG_PATTERN = Pattern.compile("<[^>]*>");
// Sends a formatted message to the player, expanding placeholders and color codes.
public static void utilitiesOGMessage(Player player, String message) {
TextUtils.utilitiesOGMessage(player, message);
}
// Expand global MiniPlaceholders recursively.
public static TextComponent expandTextWithPlaceholders(String message) {
// Process any legacy color codes.
message = processColorCodes(message);
// Use global MiniPlaceholders for the resolver.
TagResolver resolver = MiniPlaceholders.getGlobalPlaceholders();
// Recursively expand the MiniPlaceholders.
return recursivelyExpandPlaceholders(message, resolver);
}
// Expand MiniPlaceholders with player-specific context recursively.
public static TextComponent expandTextWithPlaceholders(String message, Player player) {
// Process legacy color codes.
message = processColorCodes(message);
// Create a resolver for global and audience-specific MiniPlaceholders.
TagResolver resolver = TagResolver.resolver(
MiniPlaceholders.getGlobalPlaceholders(),
MiniPlaceholders.getAudiencePlaceholders(player)
);
// Recursively expand MiniPlaceholders using MiniMessage.
return recursivelyExpandPlaceholders(message, resolver);
}
// Relational placeholder expansion between two players.
public static TextComponent expandTextWithPlaceholders(String message, Player player, Player target) {
// Process legacy color codes.
message = processColorCodes(message);
// Create a resolver for global, audience, and relational MiniPlaceholders.
TagResolver resolver = TagResolver.resolver(
MiniPlaceholders.getGlobalPlaceholders(),
MiniPlaceholders.getAudiencePlaceholders(player),
MiniPlaceholders.getRelationalPlaceholders(player, target));
// Recursively expand MiniPlaceholders using MiniMessage.
return recursivelyExpandPlaceholders(message, resolver);
}
// Recursive placeholder expansion using MiniMessage.
private static TextComponent recursivelyExpandPlaceholders(String message, TagResolver resolver) {
String previousMessage;
Component expandedMessage;
// Loop until no new MiniPlaceholders are found (to handle recursive expansions).
do {
previousMessage = message;
expandedMessage = MiniMessage.miniMessage().deserialize(message, resolver);
// Serialize back to string.
message = MiniMessage.miniMessage().serialize(expandedMessage);
}
while (! message.equals(previousMessage));
return (TextComponent) expandedMessage;
}
// Process color codes, converting legacy Bukkit color codes (e.g., &c) to MiniMessage-compatible codes.
public static String processColorCodes(String message) {
// Keeps track of the ampersand count in the loop.
int count = 0;
// Count the number of ampersand characters to determine how many there are for lowercase conversion.
for (char c : message.toCharArray()) {
// If the character is an ampersand, do this...
if (c == '&') {
// Increase the ampersand count by 1.
count++;
}
}
// Keeps track of the positions of '&' characters in the message String.
int[] positions = new int[count];
// Keep track of the position of the metaphorical cursor in the message String.
int index = 0;
// Iterate through the message String to find the positions of '&' characters for lowercase conversion.
for (int i = 0; i < message.length(); i++) {
// If the character is an ampersand, do this...
if (message.charAt(i) == '&') {
// If the character directly after the ampersand is a valid uppercase Bukkit color code, do this...
if (isUpperBukkitCode(message.charAt(i + 1))) {
// Replace the valid uppercase Bukkit color code with the equivalent lowercase one.
message = replaceAtIndex(message, (i + 1), Character.toString(Character.toLowerCase(message.charAt(i + 1))));
}
try {
// Convert the newly uniform legacy Bukkit color codes into modern MiniMessage color / formatting codes.
message = replaceAtIndex(message, (i + 1), ColorCodeMap.toMiniMessage(message.charAt(i + 1)));
// Delete the leftover ampersand.
message = replaceAtIndex(message, i, "");
}
catch (NullPointerException error) {
// Do nothing, ampersand is intended to be in the message, since it's not a valid color code.
}
// Move the metaphorical cursor forward by one.
positions[index++] = i;
}
}
// Return the processed message with modern color codes.
return message;
}
// Strips color codes and MiniMessage tags from a String.
public static String stripColors(String input) {
if (input == null) {
return null;
}
String stripped = MINIMESSAGE_TAG_PATTERN.matcher(input).replaceAll("");
return LEGACY_COLOR_PATTERN.matcher(stripped).replaceAll("");
}
// Sends an error message to the player if they lack the required permission.
public static void permissionsErrorMessage(Player player, String command, String permission) {
utilitiesOGMessage(player, "&cERROR: You do not have permission to run /" + command + ". &6Required permission: &e" + permission);
}
// Logs a Component message to the console, stripping any colors.
public static void logToConsole(String message) {
Bukkit.getLogger().info(stripColors(message));
}
// Detects if a Bukkit color code is uppercase (e.g., &C, &L).
private static boolean isUpperBukkitCode(char input) {
return "ABCDEFKLMNOR".indexOf(Character.toUpperCase(input)) != -1;
}
// Replaces a character in a string at a given index with a new String.
private static String replaceAtIndex(String original, int index, String newString) {
if (index >= 0 && index < original.length()) {
return original.substring(0, index) + newString + original.substring(index + 1);
}
return original;
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ name: Utilities-OG
authors: [ christianniehaus, NotAlexNoyle ]
version: '${version}'
api-version: '${apiVersion}'
main: me.barny1094875.utilitiesog.UtilitiesOG
main: net.trueog.utilitiesog.UtilitiesOG
depend: [ MiniPlaceholders, WorldGuard ]
commands:
utilities: