89 Commits
Author SHA1 Message Date
XiaoMoMi 0387b30149 add option to force sync tags 2026-04-19 01:24:00 +08:00
XiaoMoMi 797b77c529 26.1 support 2026-04-19 01:02:09 +08:00
XiaoMoMi 2e689cabb1 fix possible NPE 2026-04-17 01:19:48 +08:00
XiaoMoMi 52f244ddf3 fix none uuid 2026-03-26 00:28:13 +08:00
XiaoMoMi 6c0a8d2788 fix cannot find player on typewrite event end 2026-03-24 01:18:59 +08:00
XiaoMoMi 0d75def1b6 add &# hex color support 2026-03-18 22:56:10 +08:00
XiaoMoMi f3c297f6d4 add newline support for calculateTextAdvance 2026-03-16 00:51:40 +08:00
XiaoMoMi ec6ff01e24 change the sequence of arguments 2026-03-10 18:19:56 +08:00
XiaoMoMi 45f8f4fcd4 3.0.38 2026-03-10 18:04:36 +08:00
XiaoMoMi 2f6beff060 add luckperms comaptibility 2026-03-10 18:00:04 +08:00
XiaoMoMi cef568b0b0 Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2026-03-10 17:47:25 +08:00
XiaoMoMi 49fa5d167b add custom command suggestion for bubbles and nameplates 2026-03-10 17:47:22 +08:00
XiaoMoMi d6bd4a1574 Merge pull request #83 from Flestiz/main
Fix ECosmetics support
2026-03-09 20:59:56 +08:00
Flestiz 67a97411b8 Fix ECosmetics support 2026-03-09 00:53:03 +03:00
XiaoMoMi 4a4d1fe979 Merge pull request #80 from jhqwqmc/patch-1
修复hmcc切换帽子高度应用错误
2026-02-22 11:33:30 +08:00
jhqwqmc d106c96280 修复hmcc切换帽子高度应用错误 2026-02-22 00:15:37 +08:00
XiaoMoMi 52331421be should use getDouble 2026-02-16 23:17:46 +08:00
XiaoMoMi 6c38fc03cc 修复竞态下id计数错误 Fix the ID counting error under race conditions. 2026-01-28 20:06:51 +08:00
XiaoMoMi aaf4beead4 fix shift_y 2026-01-21 18:46:20 +08:00
XiaoMoMi 8fb63a90be Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2026-01-17 02:26:17 +08:00
XiaoMoMi bc83aa46c5 zelchat 2026-01-17 02:26:13 +08:00
XiaoMoMi fcc6d2bdc5 Merge pull request #77 from jhqwqmc/main
添加HMCCosmetics支持
2026-01-15 22:37:24 +08:00
jhqwqmc 83f6a0139f 修改为hat-height键 2026-01-15 21:57:22 +08:00
jhqwqmc 9b74a7bb59 添加HMCCosmetics支持 2026-01-15 21:42:45 +08:00
XiaoMoMi 22c5c61144 Merge pull request #75 from mrjimin/main
add ko_kr
2026-01-15 02:15:18 +08:00
mrjimin 741e043b17 add ko_kr 2026-01-14 23:16:58 +09:00
XiaoMoMi a4e730890a try adding ZelChat compatibility 2026-01-12 22:20:07 +08:00
XiaoMoMi 19e30bc29b remove eventLoop.submit 2025-12-29 19:27:24 +08:00
XiaoMoMi 1e5e3bea2c Update BukkitCustomNameplates.java 2025-12-28 02:49:23 +08:00
XiaoMoMi 8e1ba461a6 fix null tracker 2025-12-20 04:07:45 +08:00
XiaoMoMi d573c9063b Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2025-12-18 03:56:31 +08:00
XiaoMoMi e2a5a5564f Update pack.mcmeta 2025-12-18 03:56:29 +08:00
XiaoMoMi 1a2a689c4c Merge pull request #73 from Hokiib/main
patch unknown repository
2025-12-15 22:12:21 +08:00
Hokiib 4be6e27bc1 patch unknown repository 2025-12-14 20:30:26 +01:00
XiaoMoMi efae3f62d6 1.21.11 2025-12-12 17:14:14 +08:00
XiaoMoMi 0f4af0938b fix carbonchat hook 2025-11-22 03:23:40 +08:00
XiaoMoMi 72b1dc8513 Update TagRendererImpl.java 2025-11-19 21:44:58 +08:00
XiaoMoMi c695226515 fix passengers on folia 2025-11-14 14:31:01 +08:00
XiaoMoMi 084f7d1edf fixed is see through 2025-10-16 03:18:18 +08:00
XiaoMoMi dafe373f81 Update gradle.properties 2025-10-15 01:55:32 +08:00
XiaoMoMi e405d1c4f1 improve rendering 2025-10-15 01:37:47 +08:00
XiaoMoMi d9ee1bbb21 1.21.10 2025-10-14 00:43:57 +08:00
XiaoMoMi 8a4b0e1c23 catch more errors 2025-09-28 02:57:50 +08:00
XiaoMoMi d9d129cd97 Update custom-placeholders.yml 2025-09-09 22:34:13 +08:00
XiaoMoMi 12060e9b59 Update NameplatesExtraExpansion.java 2025-09-07 20:28:09 +08:00
XiaoMoMi 491ad32466 fix name() NPE 2025-09-07 03:33:00 +08:00
XiaoMoMi 7932423628 Merge pull request #67 from iqtesterr/main
Add ECosmetics Support
2025-08-21 20:57:13 +08:00
iqtester 2036b13524 Add ECosmetics Support 2025-08-20 17:09:41 -04:00
XiaoMoMi 99a9afb1c7 update itemsadder api version 2025-08-08 03:01:01 +08:00
XiaoMoMi 486b96d232 Update gradle.properties 2025-08-05 21:51:28 +08:00
XiaoMoMi f505d0da34 fix mongodb user & password 2025-08-05 19:04:57 +08:00
XiaoMoMi 9c77cf6878 try fix pet names 2025-08-02 04:13:27 +08:00
XiaoMoMi df5a1faa19 3.0.30 2025-07-19 23:48:06 +08:00
XiaoMoMi 2ebb781721 1.21.6 2025-06-30 02:05:35 +08:00
XiaoMoMi 3cbf4698ed add strip color codes support 2025-06-21 00:20:01 +08:00
XiaoMoMi e01dec757e allow capital letters 2025-05-29 01:18:08 +08:00
XiaoMoMi 857e5bedc9 Merge pull request #60 from Mimexe/patch-1
Remove proxy settings
2025-05-21 16:17:02 +08:00
Mime 4ac11deb07 Remove proxy settings 2025-05-20 22:36:48 +02:00
XiaoMoMi 9f657166ff bump adventure platform version 2025-05-12 03:25:38 +08:00
XiaoMoMi 687908defc fix team visibility on 1.21.5 2025-05-03 15:07:56 +08:00
XiaoMoMi 5520dc3c4e Update gradle.properties 2025-05-01 11:08:34 +08:00
XiaoMoMi 3b6542858c 3.0.26.2 2025-04-26 17:03:13 +08:00
XiaoMoMi 75982b67a1 update chat control hook 2025-04-24 03:44:40 +08:00
XiaoMoMi f1adb436d0 make player not weak reference 2025-04-23 04:49:35 +08:00
XiaoMoMi c25e222187 3.0.26 2025-04-20 16:18:21 +08:00
XiaoMoMi 8f23416ed6 fix zh_cn translation 2025-04-19 16:09:01 +08:00
XiaoMoMi 85a399eda0 3.0.26 2025-04-13 00:01:56 +08:00
XiaoMoMi 01463d554c Update AbstractCNPlayer.java 2025-04-04 16:17:08 +08:00
XiaoMoMi 29de340676 added native adventure component support 2025-03-28 20:11:29 +08:00
XiaoMoMi ebca2deef5 added npex static 2025-03-22 23:05:15 +08:00
XiaoMoMi f5bc4fda2d Remove deprecated CraftEngine integration 2025-03-15 22:06:22 +08:00
XiaoMoMi 0328c534c4 3.0.24 2025-03-09 02:24:09 +08:00
XiaoMoMi 4d0fab7b68 Update NameplatesForcePreviewCommand.java 2025-03-06 21:39:14 +08:00
XiaoMoMi a2f0591e29 Fixed Proxy Settings 2025-03-04 02:29:52 +08:00
XiaoMoMi 5a3c320995 Fixed Placeholders in Chat Prefix/Suffix 2025-03-02 19:34:10 +08:00
XiaoMoMi fd19b99e77 Added smallfont Placeholder 2025-02-24 16:26:48 +08:00
XiaoMoMi 4e5dcad309 Update gradle.properties 2025-02-21 18:51:29 +08:00
XiaoMoMi fd2c810d21 Bump Adventure Version 2025-02-21 18:50:29 +08:00
XiaoMoMi 4bf9a00b32 Fixed spigot mapping 2025-02-21 18:26:27 +08:00
XiaoMoMi 8c0272acc7 delay load 2025-02-18 00:18:51 +08:00
XiaoMoMi f8a8ce0f43 3.0.20 2025-02-14 02:34:48 +08:00
XiaoMoMi 1147deaa73 fix createTextWithImage 2025-02-08 20:50:26 +08:00
XiaoMoMi 1bc4ab6258 fix 2025-01-29 14:59:41 +08:00
XiaoMoMi a95ea99a55 Update build.gradle.kts 2025-01-27 00:05:41 +08:00
XiaoMoMi 6dbc6bf596 Update README.md 2025-01-26 23:27:46 +08:00
XiaoMoMi 63ec5e8a92 Update README.md 2025-01-26 23:24:44 +08:00
XiaoMoMi 8c1a858e2a merge modules 2025-01-26 23:20:27 +08:00
XiaoMoMi 88e4af721b update docs 2025-01-26 21:03:31 +08:00
XiaoMoMi b41e1bd2ab Update gradle.properties 2025-01-25 17:53:49 +08:00
265 changed files with 5912 additions and 1740 deletions

No files matched your search

+3 -38
View File
@@ -1,7 +1,6 @@
# Custom-Nameplates
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/Xiao-MoMi/Custom-Nameplates)
[![](https://jitpack.io/v/Xiao-MoMi/Custom-Nameplates.svg)](https://jitpack.io/#Xiao-MoMi/Custom-Nameplates)
<a href="https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates" alt="GitBook">
<img src="https://img.shields.io/badge/docs-gitbook-brightgreen" alt="Gitbook"/>
</a>
@@ -25,7 +24,7 @@ Get the artifact under /target folder
## How to Contribute
#### Translations
Clone this project and create a new language file in the /common/src/main/resources/translations directory. \
Clone this project and create a new language file in the /backend/src/main/resources/translations directory. \
Once your changes are ready, open a pull request for review. We appreciate your works!
## Support the Developer
@@ -36,47 +35,13 @@ Afdian: https://afdian.com/@xiaomomi/
## CustomNameplates API
### Maven
```html
<repositories>
<repository>
<id>jitpack</id>
<url>https://jitpack.io/</url>
</repository>
</repositories>
```
```html
<dependencies>
<dependency>
<groupId>com.github.Xiao-MoMi</groupId>
<artifactId>Custom-Nameplates</artifactId>
<version>{VERSION}</version>
<scope>provided</scope>
</dependency>
</dependencies>
```
### Gradle (Groovy)
```groovy
repositories {
maven { url 'https://jitpack.io' }
}
```
```groovy
dependencies {
compileOnly 'com.github.Xiao-MoMi:Custom-Nameplates:{VERSION}'
}
```
### Gradle (Kotlin)
```kotlin
repositories {
maven("https://jitpack.io/")
maven("https://repo.momirealms.net/releases/")
}
```
```kotlin
dependencies {
compileOnly("com.github.Xiao-MoMi:Custom-Nameplates:{VERSION}")
compileOnly("net.momirealms:custom-nameplates:3.0.19")
}
```
+45 -12
View File
@@ -1,5 +1,4 @@
plugins {
id("io.github.goooler.shadow") version "8.1.8"
id("maven-publish")
}
@@ -10,53 +9,87 @@ repositories {
}
dependencies {
implementation(project(":common"))
// Adventure
implementation("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-serializer-json-legacy-impl:${rootProject.properties["adventure_bundle_version"]}")
// YAML
implementation(files("libs/boosted-yaml-${rootProject.properties["boosted_yaml_version"]}.jar"))
// Cache
compileOnly("com.github.ben-manes.caffeine:caffeine:${rootProject.properties["caffeine_version"]}")
// Netty
compileOnly("io.netty:netty-all:4.1.113.Final")
compileOnly("io.netty:netty-all:4.1.117.Final")
// GSON
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
// Fast util
compileOnly("it.unimi.dsi:fastutil:${rootProject.properties["fastutil_version"]}")
// Command
compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}")
compileOnly("org.incendo:cloud-minecraft-extras:${rootProject.properties["cloud_minecraft_extras_version"]}")
// Logger
compileOnly("org.slf4j:slf4j-api:${rootProject.properties["slf4j_version"]}")
compileOnly("org.apache.logging.log4j:log4j-core:${rootProject.properties["log4j_version"]}")
// Expression
compileOnly("net.objecthunter:exp4j:${rootProject.properties["exp4j_version"]}")
// code generator
compileOnly("net.bytebuddy:byte-buddy:${rootProject.properties["byte_buddy_version"]}")
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
toolchain {
languageVersion = JavaLanguageVersion.of(17)
languageVersion = JavaLanguageVersion.of(21)
}
withSourcesJar()
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(17)
options.release.set(21)
dependsOn(tasks.clean)
}
tasks {
shadowJar {
archiveClassifier = ""
archiveFileName = "CustomNameplates-${rootProject.properties["project_version"]}.jar"
archiveClassifier.set("")
archiveFileName = "custom-nameplates-${rootProject.properties["project_version"]}.jar"
relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
relocate("dev.dejvokep", "net.momirealms.customnameplates.libraries")
}
}
publishing {
repositories {
maven {
url = uri("https://repo.momirealms.net/releases")
credentials(PasswordCredentials::class) {
username = System.getenv("REPO_USERNAME")
password = System.getenv("REPO_PASSWORD")
}
}
}
publications {
create<MavenPublication>("mavenJava") {
groupId = "net.momirealms"
artifactId = "CustomNameplates"
version = rootProject.version.toString()
artifact(tasks.shadowJar)
artifactId = "custom-nameplates"
version = rootProject.properties["project_version"].toString()
artifact(tasks["sourcesJar"])
from(components["shadow"])
pom {
name = "CustomNameplates API"
url = "https://github.com/Xiao-MoMi/Custom-Nameplates"
licenses {
license {
name = "GNU General Public License v3.0"
url = "https://www.gnu.org/licenses/gpl-3.0.html"
distribution = "repo"
}
}
}
}
}
}
@@ -33,18 +33,33 @@ import net.momirealms.customnameplates.api.storage.data.PlayerData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public abstract class AbstractCNPlayer implements CNPlayer {
/**
* Player instance adapted by CustomNameplates
*/
public abstract class AbstractCNPlayer<P> implements CNPlayer {
/**
* The CustomNameplates plugin
*/
protected final CustomNameplates plugin;
/**
* Player netty channel
*/
protected final Channel channel;
protected Object player;
/**
* Platform player instance
*/
protected P player;
protected UUID uuid;
protected int entityId;
protected String name;
private volatile boolean isLoaded = false;
private volatile boolean tempPreviewing = false;
@@ -69,8 +84,14 @@ public abstract class AbstractCNPlayer implements CNPlayer {
private final Map<CNPlayer, Tracker> trackers = new WeakHashMap<>();
private final ReadWriteLock trackerLock = new ReentrantReadWriteLock();
private final List<String> otherActionBarFeatures = new ArrayList<>();
private final Vector<String> otherActionBarFeatures = new Vector<>();
/**
* Creates a player instance
*
* @param plugin CustomNameplates plugin
* @param channel netty channel
*/
protected AbstractCNPlayer(CustomNameplates plugin, Channel channel) {
this.plugin = plugin;
this.channel = channel;
@@ -204,6 +225,9 @@ public abstract class AbstractCNPlayer implements CNPlayer {
}
}
/**
* Reload the player instance, clear caches
*/
public void reload() {
cachedValues.clear();
cachedRelationalValues.clear();
@@ -214,7 +238,12 @@ public abstract class AbstractCNPlayer implements CNPlayer {
feature2Placeholders.clear();
}
public void setPlayer(Object player) {
/**
* Sets the platform player instance on join
*
* @param player player
*/
public void setPlayer(P player) {
this.player = player;
}
@@ -233,10 +262,20 @@ public abstract class AbstractCNPlayer implements CNPlayer {
return player;
}
/**
* Sets if the player data is loaded
*
* @param loaded loaded or not
*/
public void setLoaded(boolean loaded) {
isLoaded = loaded;
}
/**
* Sets if the player is temporarily previewing the nameplate
*
* @param previewing is previewing or not
*/
public void setTempPreviewing(boolean previewing) {
this.tempPreviewing = previewing;
}
@@ -246,6 +285,11 @@ public abstract class AbstractCNPlayer implements CNPlayer {
return tempPreviewing;
}
/**
* Sets if the player is using toggle command to preview his nameplate
*
* @param previewing is previewing or not
*/
public void setToggleablePreviewing(boolean previewing) {
this.toggleablePreviewing = previewing;
}
@@ -404,7 +448,12 @@ public abstract class AbstractCNPlayer implements CNPlayer {
return false;
}
} else {
boolean satisfied = requirement.isSatisfied(this, this);
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, this);
} catch (Exception e) {
satisfied = false;
}
data.updateTicks(false);
data.data(satisfied);
if (!satisfied) {
@@ -412,7 +461,12 @@ public abstract class AbstractCNPlayer implements CNPlayer {
}
}
} else {
boolean satisfied = requirement.isSatisfied(this, this);
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, this);
} catch (Exception e) {
satisfied = false;
}
data = new TimeStampData<>(satisfied, currentTicks, true);
cachedRequirements.put(requirement.countId(), data);
if (!satisfied) {
@@ -435,7 +489,12 @@ public abstract class AbstractCNPlayer implements CNPlayer {
return false;
}
} else {
boolean satisfied = requirement.isSatisfied(this, another);
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, another);
} catch (Exception e) {
satisfied = false;
}
data.updateTicks(false);
data.data(satisfied);
if (!satisfied) {
@@ -443,7 +502,12 @@ public abstract class AbstractCNPlayer implements CNPlayer {
}
}
} else {
boolean satisfied = requirement.isSatisfied(this, another);
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, another);
} catch (Exception e) {
satisfied = false;
}
data = new TimeStampData<>(satisfied, currentTicks, true);
innerMap.put(another, data);
if (!satisfied) {
@@ -599,12 +663,15 @@ public abstract class AbstractCNPlayer implements CNPlayer {
@Override
public void save() {
plugin.getStorageManager().dataSource().updatePlayerData(PlayerData.builder()
this.plugin.getStorageManager().dataSource().updatePlayerData(
PlayerData.builder()
.uuid(uuid())
.nameplate(nameplateData())
.bubble(bubbleData())
.previewTags(isToggleablePreviewing())
.build(), plugin.getScheduler().async());
.build(),
this.plugin.getScheduler().async()
);
}
@Override
@@ -624,4 +691,19 @@ public abstract class AbstractCNPlayer implements CNPlayer {
public int hashCode() {
return entityID();
}
@Override
public String name() {
return Optional.ofNullable(this.name).orElse("");
}
@Override
public UUID uuid() {
return this.uuid;
}
@Override
public int entityID() {
return this.entityId;
}
}
@@ -36,6 +36,9 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* CustomNameplates Player
*/
public interface CNPlayer {
/**
@@ -29,6 +29,7 @@ import dev.dejvokep.boostedyaml.utils.format.NodeRole;
import net.momirealms.customnameplates.api.feature.CharacterArranger;
import net.momirealms.customnameplates.api.feature.bossbar.BossBar;
import net.momirealms.customnameplates.api.helper.AdventureHelper;
import net.momirealms.customnameplates.api.helper.VersionHelper;
import net.momirealms.customnameplates.common.locale.TranslationManager;
import net.momirealms.customnameplates.common.plugin.CustomNameplatesProperties;
import net.momirealms.customnameplates.common.plugin.config.ConfigLoader;
@@ -42,10 +43,27 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
/**
* Manages the loading and handling of configuration files for the Custom Nameplates plugin.
*/
public abstract class ConfigManager implements ConfigLoader, Reloadable {
/**
* The main configuration document that stores all settings for the plugin.
* <p>
* This document is loaded during the initialization of the plugin and is used to retrieve various configuration values.
* </p>
*/
private static YamlDocument MAIN_CONFIG;
/**
* Returns the main configuration document.
* <p>
* If the configuration has not been loaded yet, an {@code IllegalStateException} will be thrown.
* </p>
*
* @return The main configuration document
* @throws IllegalStateException If the configuration has not been loaded
*/
public static YamlDocument getMainConfig() {
if (MAIN_CONFIG == null) {
throw new IllegalStateException("Main config not loaded");
@@ -53,79 +71,300 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
return MAIN_CONFIG;
}
/**
* The singleton instance of the {@code ConfigManager}.
*/
private static ConfigManager instance;
/**
* The {@code CustomNameplates} plugin instance associated with this {@code ConfigManager}.
*/
protected final CustomNameplates plugin;
/**
* Indicates whether debugging is enabled.
*/
protected boolean debug;
/**
* Indicates whether plugin updates are checked automatically.
*/
protected boolean checkUpdate;
/**
* Metrics flag to enable or disable the metrics system.
*/
protected boolean metrics;
/**
* Flag to enable or disable the nametag module.
*/
protected boolean nametagModule;
/**
* Flag to enable or disable the action bar module.
*/
protected boolean actionbarModule;
/**
* Flag to enable or disable the image module.
*/
protected boolean imageModule;
/**
* Flag to enable or disable the boss bar module.
*/
protected boolean bossBarModule;
/**
* Flag to enable or disable the bubble module.
*/
protected boolean bubbleModule;
/**
* Flag to enable or disable the nameplate module.
*/
protected boolean nameplateModule;
/**
* Flag to enable or disable the background module.
*/
protected boolean backgroundModule;
/**
* Flag to hide or display team names.
*/
protected boolean hideTeamNames;
/**
* The default placeholder refresh interval (in seconds).
*/
protected int defaultPlaceholderRefreshInterval;
/**
* The default condition refresh interval (in seconds).
*/
protected int defaultConditionRefreshInterval;
/**
* The delay (in milliseconds) before sending updates.
*/
protected int delaySend;
/**
* Flag to catch other action bar events.
*/
protected boolean catchOtherActionBar;
/**
* Flag to display system chat messages.
*/
protected boolean displaySystemChat;
/**
* The duration (in seconds) that other action bars will stay visible.
*/
protected int otherActionBarStayTime;
/**
* The namespace used for resource identification.
*/
protected String namespace;
/**
* The font used for rendering text.
*/
protected String font;
/**
* Flag to generate configurations on plugin start.
*/
protected boolean generateOnStart;
/**
* The initial character used in text or formatting.
*/
protected char initialChar;
/**
* The path to the image resource.
*/
protected String imagePath;
/**
* The path to the nameplate resource.
*/
protected String nameplatePath;
/**
* The path to the bubble resource.
*/
protected String bubblePath;
/**
* The path used for splitting space resources.
*/
protected String spaceSplitPath;
/**
* The path to the background resource.
*/
protected String backgroundPath;
/**
* Flag to enable or disable shader effects.
*/
protected boolean enableShader;
/**
* Flag to hide or show scoreboard numbers.
*/
protected boolean hideScoreBoardNumber;
/**
* Flag to enable or disable animated text.
*/
protected boolean animatedText;
/**
* Flag to enable or disable the ItemsAdder effect.
*/
protected boolean itemsAdderEffect;
/**
* The color used for the boss bar when removed.
*/
protected BossBar.Color removedBarColor;
/**
* Flag to enable compatibility for version 1.20.2 of Minecraft.
*/
protected boolean bossBar1_20_2;
/**
* Flag to enable compatibility for version 1.17 of Minecraft.
*/
protected boolean bossBar1_17;
/**
* Flag to enable or disable legacy Unicode support.
*/
protected boolean legacyUnicodes;
/**
* Flag to enable or disable ItemsAdder pack.
*/
protected boolean packItemsAdder;
/**
* Flag to enable or disable legacy ItemsAdder pack.
*/
protected boolean packItemsAdderLegacy;
/**
* Flag to enable or disable Oraxen pack.
*/
protected boolean packOraxen;
/**
* Flag to enable or disable Nexo pack.
*/
protected boolean packNexo;
/**
* Flag to enable or disable Creative Central pack.
*/
protected boolean packCreativeCentral;
/**
* Flag to enable or disable CraftEngine pack.
*/
protected boolean packCraftEngine;
/**
* Flag to enable or disable unsafe chat features.
*/
protected boolean chatUnsafe;
/**
* Flag to enable or disable chat features for TR (text roleplay).
*/
protected boolean chatTR;
/**
* Flag to enable or disable chat features for Venture.
*/
protected boolean chatVenture;
/**
* Flag to enable or disable chat features for Husk.
*/
protected boolean chatHusk;
/**
* Flag to enable or disable chat features for Carbon.
*/
protected boolean chatCarbon;
/**
* Flag to enable or disable chat features for Advanced.
*/
protected boolean chatAdvanced;
/**
* Flag to enable or disable chat features for Essentials.
*/
protected boolean chatEss;
/**
* Flag to enable or disable chat features for ChatControlRed.
*/
protected boolean chatChatControlRed;
/**
* Flag to enable or disable chat features for Chatty.
*/
protected boolean chatChatty;
/**
* Flag to enable or disable chat features for Zel.
*/
protected boolean chatZel;
/**
* Flag to enable or disable dialogue features for TW (text world).
*/
protected boolean twDialogue;
/**
* Flag to enable or disable cinematic features for TW (text world).
*/
protected boolean twCinematic;
/**
* The version of the current configuration.
*/
protected String configVersion;
protected int forceUpdatePassengerInterval;
protected float minPackVersion;
protected boolean stripChatColorTags;
/**
* Constructs a new {@code ConfigManager} for the specified {@code CustomNameplates} plugin instance.
*
* @param plugin The {@code CustomNameplates} plugin instance
*/
public ConfigManager(CustomNameplates plugin) {
this.plugin = plugin;
instance = this;
}
/**
* Loads the configuration file from the specified path and initializes various settings.
* <p>
* This method reads the {@code config.yml} file and sets up all configuration options such as modules,
* integrations, and resource packs. It also handles versioning and saves the loaded configuration back
* to the file system.
* </p>
*
* @throws RuntimeException If an error occurs while loading or saving the configuration
*/
@Override
public void load() {
configVersion = CustomNameplatesProperties.getValue("config");
@@ -163,6 +402,13 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
loadSettings();
}
/**
* Loads the settings from the configuration document into various fields.
* <p>
* This method parses the {@code MAIN_CONFIG} document and assigns values to the class fields.
* It also applies settings such as locale and legacy support.
* </p>
*/
private void loadSettings() {
YamlDocument config = MAIN_CONFIG;
AdventureHelper.legacySupport = config.getBoolean("other-settings.legacy-color-code-support", true);
@@ -189,7 +435,7 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
packOraxen = config.getBoolean("integrations.resource-pack.Oraxen", false);
packCreativeCentral = config.getBoolean("integrations.resource-pack.Creative-Central");
packNexo = config.getBoolean("integrations.resource-pack.Nexo");
packCraftEngine = config.getBoolean("integrations.resource-pack.CraftEngine", false);
packCraftEngine = false;
chatUnsafe = config.getBoolean("other-settings.unsafe-chat-event", false);
chatEss = config.getBoolean("integrations.chat.Essentials", false);
@@ -200,6 +446,7 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
chatVenture = config.getBoolean("integrations.chat.VentureChat", false);
chatChatControlRed = config.getBoolean("integrations.chat.ChatControlRed", false);
chatChatty = config.getBoolean("integrations.chat.Chatty", false);
chatZel = config.getBoolean("integrations.chat.ZelChat", false);
twDialogue = config.getBoolean("integrations.typewriter.dialogue", true);
twCinematic = config.getBoolean("integrations.typewriter.cinematic", true);
@@ -228,6 +475,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
legacyUnicodes = config.getBoolean("resource-pack.legacy-unicodes", true);
minPackVersion = getVersion(config.getString("resource-pack.supported-version.min", "SERVER_VERSION"));
// Other settings
delaySend = config.getInt("other-settings.send-delay", 0);
defaultPlaceholderRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 1);
@@ -236,6 +485,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
otherActionBarStayTime = config.getInt("other-settings.other-actionbar-stay-time", 3000);
displaySystemChat = config.getBoolean("other-settings.display-system-actionbar", true);
hideTeamNames = config.getBoolean("other-settings.hide-team-names", true);
stripChatColorTags = config.getBoolean("other-settings.strip-chat-color-tags", false);
forceUpdatePassengerInterval = config.getInt("other-settings.force-update-passenger-interval", -1);
}
@Override
@@ -243,217 +494,471 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
Reloadable.super.unload();
}
private static float getVersion(String version) {
if (version.equalsIgnoreCase("SERVER_VERSION")) {
return VersionHelper.version();
}
String[] split = version.split("\\.", 2);
if (split.length != 2) {
throw new IllegalArgumentException("Invalid version: " + version);
}
return Float.parseFloat(split[1]);
}
public static float minPackVersion() {
return instance.minPackVersion;
}
/**
* Retrieves the delay before sending updates.
* @return the delay time (in milliseconds).
*/
public static int delaySend() {
return instance.delaySend;
}
/**
* Retrieves the path used for splitting space resources.
* @return the space split path.
*/
public static String spaceSplitPath() {
return instance.spaceSplitPath;
}
/**
* Retrieves the path to the bubble resource.
* @return the bubble path.
*/
public static String bubblePath() {
return instance.bubblePath;
}
/**
* Retrieves the path to the image resource.
* @return the image path.
*/
public static String imagePath() {
return instance.imagePath;
}
/**
* Retrieves the path to the background resource.
* @return the background path.
*/
public static String backgroundPath() {
return instance.backgroundPath;
}
/**
* Retrieves the path to the nameplate resource.
* @return the nameplate path.
*/
public static String nameplatePath() {
return instance.nameplatePath;
}
/**
* Retrieves whether configuration generation is enabled on startup.
* @return true if configuration generation is enabled on start; false otherwise.
*/
public static boolean generateOnStart() {
return instance.generateOnStart;
}
/**
* Retrieves the namespace used for resource identification.
* @return the namespace.
*/
public static String namespace() {
return instance.namespace;
}
/**
* Retrieves the font used for rendering text.
* @return the font.
*/
public static String font() {
return instance.font;
}
/**
* Retrieves the version of the current configuration.
* @return the config version.
*/
public static String configVersion() {
return instance.configVersion;
}
/**
* Retrieves the initial character used for formatting.
* @return the initial character.
*/
public static char initialChar() {
return instance.initialChar;
}
/**
* Retrieves whether team names are hidden.
* @return true if team names are hidden; false otherwise.
*/
public static boolean hideTeamNames() {
return instance.hideTeamNames;
}
/**
* Retrieves whether the action bar module is enabled.
* @return true if the action bar module is enabled; false otherwise.
*/
public static boolean actionbarModule() {
return instance.actionbarModule;
}
/**
* Retrieves whether the nametag module is enabled.
* @return true if the nametag module is enabled; false otherwise.
*/
public static boolean nametagModule() {
return instance.nametagModule;
}
/**
* Retrieves whether other action bars should be caught.
* @return true if other action bars are caught; false otherwise.
*/
public static boolean catchOtherActionBar() {
return instance.catchOtherActionBar;
}
/**
* Retrieves whether system chat should be displayed.
* @return true if system chat is displayed; false otherwise.
*/
public static boolean displaySystemChat() {
return instance.displaySystemChat;
}
/**
* Retrieves whether the ItemsAdder pack is enabled.
* @return true if the ItemsAdder pack is enabled; false otherwise.
*/
public static boolean packItemsAdder() {
return instance.packItemsAdder;
}
/**
* Retrieves whether the legacy ItemsAdder pack is enabled.
* @return true if the legacy ItemsAdder pack is enabled; false otherwise.
*/
public static boolean packItemsAdderLegacy() {
return instance.packItemsAdderLegacy;
}
/**
* Retrieves whether the Oraxen pack is enabled.
* @return true if the Oraxen pack is enabled; false otherwise.
*/
public static boolean packOraxen() {
return instance.packOraxen;
}
/**
* Retrieves whether the Nexo pack is enabled.
* @return true if the Nexo pack is enabled; false otherwise.
*/
public static boolean packNexo() {
return instance.packNexo;
}
/**
* Retrieves whether the CraftEngine pack is enabled.
* @return true if the CraftEngine pack is enabled; false otherwise.
*/
public static boolean packCraftEngine() {
return instance.packCraftEngine;
}
public static boolean packCreativeCentral() { return instance.packCreativeCentral; }
/**
* Retrieves whether the Creative Central pack is enabled.
* @return true if the Creative Central pack is enabled; false otherwise.
*/
public static boolean packCreativeCentral() {
return instance.packCreativeCentral;
}
/**
* Retrieves whether the scoreboard numbers should be hidden.
* @return true if scoreboard numbers are hidden; false otherwise.
*/
public static boolean hideScoreBoardNumber() {
return instance.hideScoreBoardNumber;
}
/**
* Retrieves whether animated text is enabled.
* @return true if animated text is enabled; false otherwise.
*/
public static boolean animatedText() {
return instance.animatedText;
}
/**
* Retrieves whether the ItemsAdder effect is enabled.
* @return true if the ItemsAdder effect is enabled; false otherwise.
*/
public static boolean itemsAdderEffect() {
return instance.itemsAdderEffect;
}
/**
* Retrieves the color to be used for a removed boss bar.
* @return the color for the removed bar.
*/
public static BossBar.Color removedBarColor() {
return instance.removedBarColor;
}
/**
* Retrieves whether the image module is enabled.
* @return true if the image module is enabled; false otherwise.
*/
public static boolean imageModule() {
return instance.imageModule;
}
/**
* Retrieves whether the boss bar module is enabled.
* @return true if the boss bar module is enabled; false otherwise.
*/
public static boolean bossbarModule() {
return instance.bossBarModule;
}
/**
* Retrieves whether the bubble module is enabled.
* @return true if the bubble module is enabled; false otherwise.
*/
public static boolean bubbleModule() {
return instance.bubbleModule;
}
/**
* Retrieves whether the background module is enabled.
* @return true if the background module is enabled; false otherwise.
*/
public static boolean backgroundModule() {
return instance.backgroundModule;
}
/**
* Retrieves whether the nameplate module is enabled.
* @return true if the nameplate module is enabled; false otherwise.
*/
public static boolean nameplateModule() {
return instance.nameplateModule;
}
/**
* Retrieves whether debugging is enabled.
* @return true if debugging is enabled; false otherwise.
*/
public static boolean debug() {
return instance.debug;
}
/**
* Retrieves whether the plugin checks for updates.
* @return true if update checks are enabled; false otherwise.
*/
public static boolean checkUpdate() {
return instance.checkUpdate;
}
/**
* Retrieves whether the metrics system is enabled.
* @return true if the metrics system is enabled; false otherwise.
*/
public static boolean metrics() {
return instance.metrics;
}
/**
* Retrieves whether dialogue features for text world (TW) are enabled.
* @return true if TW dialogue is enabled; false otherwise.
*/
public static boolean twDialogue() {
return instance.twDialogue;
}
/**
* Retrieves whether cinematic features for text world (TW) are enabled.
* @return true if TW cinematic is enabled; false otherwise.
*/
public static boolean twCinematic() {
return instance.twCinematic;
}
/**
* Retrieves the default placeholder refresh interval (in seconds).
* @return the default placeholder refresh interval.
*/
public static int defaultPlaceholderRefreshInterval() {
return instance.defaultPlaceholderRefreshInterval;
}
/**
* Retrieves the default condition refresh interval (in seconds).
* @return the default condition refresh interval.
*/
public static int defaultConditionRefreshInterval() {
return instance.defaultConditionRefreshInterval;
}
/**
* Retrieves the duration (in seconds) that other action bars will stay visible.
* @return the duration for other action bars to stay visible.
*/
public static int otherActionBarStayTime() {
return instance.otherActionBarStayTime;
}
/**
* Retrieves whether shader effects are enabled.
* @return true if shader effects are enabled; false otherwise.
*/
public static boolean enableShader() {
return instance.enableShader;
}
/**
* Retrieves whether legacy Unicode support is enabled.
* @return true if legacy Unicode support is enabled; false otherwise.
*/
public static boolean legacyUnicodes() {
return instance.legacyUnicodes;
}
/**
* Retrieves whether compatibility with Minecraft 1.20.2 is enabled for the boss bar.
* @return true if the boss bar is compatible with Minecraft 1.20.2; false otherwise.
*/
public static boolean bossBar1_20_2() {
return instance.bossBar1_20_2;
}
/**
* Retrieves whether compatibility with Minecraft 1.17 is enabled for the boss bar.
* @return true if the boss bar is compatible with Minecraft 1.17; false otherwise.
*/
public static boolean bossBar1_17() {
return instance.bossBar1_17;
}
/**
* Retrieves whether unsafe chat features are enabled.
* @return true if unsafe chat is enabled; false otherwise.
*/
public static boolean chatUnsafe() {
return instance.chatUnsafe;
}
/**
* Retrieves whether TrChat features are enabled.
* @return true if TR chat is enabled; false otherwise.
*/
public static boolean chatTrChat() {
return instance.chatTR;
}
/**
* Retrieves whether VentureChat features are enabled.
* @return true if Venture chat is enabled; false otherwise.
*/
public static boolean chatVenture() {
return instance.chatVenture;
}
/**
* Retrieves whether HuskChat features are enabled.
* @return true if Husk chat is enabled; false otherwise.
*/
public static boolean chatHusk() {
return instance.chatHusk;
}
/**
* Retrieves whether Essentials chat features are enabled.
* @return true if Essentials chat is enabled; false otherwise.
*/
public static boolean chatEss() {
return instance.chatEss;
}
/**
* Retrieves whether CarbonChat features are enabled.
* @return true if Carbon chat is enabled; false otherwise.
*/
public static boolean chatCarbon() {
return instance.chatCarbon;
}
/**
* Retrieves whether AdvancedChat features are enabled.
* @return true if Advanced chat is enabled; false otherwise.
*/
public static boolean chatAdvanced() {
return instance.chatAdvanced;
}
/**
* Retrieves whether RedChatControl is enabled.
* @return true if Red chat control is enabled; false otherwise.
*/
public static boolean chatChatControlRed() {
return instance.chatChatControlRed;
}
/**
* Retrieves whether Chatty chat features are enabled.
* @return true if Chatty chat is enabled; false otherwise.
*/
public static boolean chatChatty() {
return instance.chatChatty;
}
/**
* Retrieves whether ZelChat chat features are enabled.
* @return true if ZelChat chat is enabled; false otherwise.
*/
public static boolean chatZel() {
return instance.chatZel;
}
public static boolean stripChatColorTags() {
return instance.stripChatColorTags;
}
public static int forceUpdatePassengerInterval() {
return instance.forceUpdatePassengerInterval;
}
/**
* Returns the configuration file at the specified path with a custom route separator.
*
* @param filePath The path to the configuration file
* @return The {@code YamlDocument} representing the loaded configuration
*/
@Override
public YamlDocument loadConfig(String filePath) {
return loadConfig(filePath, '.');
}
/**
* Returns the configuration file at the specified path with a custom route separator.
*
* @param filePath The path to the configuration file
* @param routeSeparator The character used to separate route segments in the YAML file
* @return The {@code YamlDocument} representing the loaded configuration
*/
@Override
public YamlDocument loadConfig(String filePath, char routeSeparator) {
try (InputStream inputStream = new FileInputStream(resolveConfig(filePath).toFile())) {
@@ -485,6 +990,17 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
}
}
/**
* Loads the configuration file from the specified file path.
*
* @param filePath the relative or absolute path to the configuration file.
* @param generalSettings settings for general YAML loading behavior.
* @param loaderSettings settings for YAML loader behavior.
* @param dumperSettings settings for YAML dumping behavior.
* @param updaterSettings settings for YAML updating behavior.
* @return a {@link YamlDocument} containing the loaded YAML content.
* @throws RuntimeException if the configuration file could not be loaded or an error occurs.
*/
@Override
public YamlDocument loadConfig(String filePath, GeneralSettings generalSettings, LoaderSettings loaderSettings, DumperSettings dumperSettings, UpdaterSettings updaterSettings) {
try (InputStream inputStream = new FileInputStream(resolveConfig(filePath).toFile())) {
@@ -502,6 +1018,13 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
}
}
/**
* Loads the YAML data from the specified file.
*
* @param file the file containing the YAML data.
* @return a {@link YamlDocument} containing the loaded YAML data.
* @throws RuntimeException if the data file could not be loaded or an error occurs.
*/
@Override
public YamlDocument loadData(File file) {
try (InputStream inputStream = new FileInputStream(file)) {
@@ -512,6 +1035,15 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
}
}
/**
* Resolves the configuration file path and ensures the file exists.
* If the configuration file does not exist, it is created from an embedded resource.
*
* @param filePath the relative or absolute path to the configuration file.
* @return the resolved {@link Path} to the configuration file.
* @throws IllegalArgumentException if the filePath is null or empty, or if the embedded resource cannot be found.
* @throws RuntimeException if an error occurs during file creation or copying.
*/
public Path resolveConfig(String filePath) {
if (filePath == null || filePath.isEmpty()) {
throw new IllegalArgumentException("ResourcePath cannot be null or empty");
@@ -17,7 +17,6 @@
package net.momirealms.customnameplates.api;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.momirealms.customnameplates.api.feature.actionbar.ActionBarManager;
import net.momirealms.customnameplates.api.feature.advance.AdvanceManager;
@@ -40,8 +39,11 @@ import net.momirealms.customnameplates.common.event.EventManager;
import net.momirealms.customnameplates.common.locale.TranslationManager;
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
import net.momirealms.customnameplates.common.plugin.scheduler.SchedulerTask;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@@ -52,34 +54,137 @@ import java.util.function.Supplier;
* Provides access to managers for various features.
*/
public abstract class CustomNameplates implements NameplatesPlugin {
private static CustomNameplates instance;
/**
* Manages the dependencies required by the plugin or system.
*/
protected DependencyManager dependencyManager;
/**
* Handles translations for the plugin, ensuring text is localized based on the player's language.
*/
protected TranslationManager translationManager;
/**
* A debugger function that logs debug information with a "[DEBUG]" prefix.
* It consumes a supplier of strings and logs the result.
*/
protected Consumer<Supplier<String>> debugger = (s) -> getPluginLogger().info("[DEBUG] " + s.get());
/**
* Manages configuration settings, loading and accessing configuration data for the plugin.
*/
protected ConfigManager configManager;
/**
* Responsible for sending packets to clients or other network entities.
*/
protected PacketSender packetSender;
/**
* Injects custom pipelines into the system to modify or handle data processing flows.
*/
protected PipelineInjector pipelineInjector;
/**
* Manages placeholders used for dynamic text replacements in the plugin's output.
*/
protected PlaceholderManager placeholderManager;
/**
* Manages requirements or conditions that must be met for certain actions or events to occur.
*/
protected RequirementManager requirementManager;
/**
* Manages the action bar, responsible for displaying dynamic text to players in the action bar.
*/
protected ActionBarManager actionBarManager;
/**
* Manages the boss bar, which displays a customizable progress bar and messages to players.
*/
protected BossBarManager bossBarManager;
/**
* Manages unlimited tags that can be applied to players, items, or other entities.
*/
protected UnlimitedTagManager unlimitedTagManager;
/**
* Represents the platform on which the plugin or system is running (e.g., Spigot, Bukkit, etc.).
*/
protected Platform platform;
/**
* The main task or process that the plugin or system executes.
*/
protected MainTask mainTask;
/**
* A scheduled task that runs alongside the main task, typically used for periodic or delayed actions.
*/
protected SchedulerTask scheduledMainTask;
protected ConcurrentHashMap<UUID, CNPlayer> onlinePlayerMap = new ConcurrentHashMap<>();
protected ConcurrentHashMap<Integer, CNPlayer> entityIDFastLookup = new ConcurrentHashMap<>();
/**
* A map that tracks online players by their unique UUID, allowing quick access to player data.
*/
protected Map<UUID, CNPlayer> onlinePlayerMap = new ConcurrentHashMap<>();
/**
* A fast lookup map that associates entity IDs to player data (CNPlayer) for quick access.
*/
protected Map<Integer, CNPlayer> entityIDFastLookup = new ConcurrentHashMap<>();
/**
* Manages advances or progressions for players, such as achievements or level ups.
*/
protected AdvanceManager advanceManager;
/**
* Manages background tasks, likely for asynchronous processing or UI updates.
*/
protected BackgroundManager backgroundManager;
/**
* Manages events and event handling within the plugin or system.
*/
protected EventManager eventManager;
/**
* Manages the plugin's data storage system, including saving and retrieving player data.
*/
protected StorageManager storageManager;
/**
* Manages bubble effects, likely for UI or visual effects displayed to players.
*/
protected BubbleManager bubbleManager;
/**
* Manages chat functionality, including message formatting, commands, and interactions.
*/
protected ChatManager chatManager;
/**
* Manages images, such as textures or images for resource packs or player displays.
*/
protected ImageManager imageManager;
/**
* Manages nameplates displayed above players or entities.
*/
protected NameplateManager nameplateManager;
/**
* Manages resource packs, allowing the plugin to send custom content to players.
*/
protected ResourcePackManager resourcePackManager;
/**
* Provides an API for external access to the plugin's functionality and data.
*/
protected CustomNameplatesAPI api;
private String buildByBit = "%%__BUILTBYBIT__%%";
@@ -89,6 +194,9 @@ public abstract class CustomNameplates implements NameplatesPlugin {
private String username = "%%__USERNAME__%%";
private boolean isLatest = false;
/**
* Creates the CustomNameplates instance
*/
protected CustomNameplates() {
instance = this;
}
@@ -357,4 +465,16 @@ public abstract class CustomNameplates implements NameplatesPlugin {
public static CustomNameplates getInstance() {
return instance;
}
@ApiStatus.Experimental
public void addPlayerUnsafe(int entityId, CNPlayer player) {
if (this.entityIDFastLookup.containsKey(entityId)) return;
this.entityIDFastLookup.put(entityId, player);
}
@Nullable
@ApiStatus.Experimental
public CNPlayer removePlayerUnsafe(int entityId) {
return this.entityIDFastLookup.remove(entityId);
}
}
@@ -30,8 +30,10 @@ import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.UUID;
/**
* CustomNameplatesAPI
*/
public record CustomNameplatesAPI(CustomNameplates plugin) {
private static CustomNameplatesAPI instance;
public CustomNameplatesAPI(CustomNameplates plugin) {
@@ -108,7 +110,7 @@ public record CustomNameplatesAPI(CustomNameplates plugin) {
text = AdventureHelper.legacyToMiniMessage(text);
}
float advance = plugin.getAdvanceManager().getLineAdvance(text);
return adaptiveImage.createImagePrefix(advance, leftMargin, rightMargin) + text + adaptiveImage.createImageSuffix(advance, leftMargin, rightMargin);
return AdventureHelper.surroundWithNameplatesFont(adaptiveImage.createImagePrefix(advance, leftMargin, rightMargin)) + text + AdventureHelper.surroundWithNameplatesFont(adaptiveImage.createImageSuffix(advance, leftMargin, rightMargin));
}
/**
@@ -0,0 +1,109 @@
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.Set;
import java.util.UUID;
public class DummyPlayer extends AbstractCNPlayer<Object> {
private final CNPlayer target;
private final int megEntityId;
private final Vector3 position;
public DummyPlayer(CustomNameplates plugin, CNPlayer delegate, int entityId, Vector3 location) {
super(plugin, delegate.channel());
this.target = delegate;
this.megEntityId = entityId;
this.position = location;
}
@Override
public int entityID() {
return this.megEntityId;
}
@Override
public boolean hasPermission(String permission) {
return this.target.hasPermission(permission);
}
@Override
public Vector3 position() {
return this.position;
}
@Override
public String world() {
return this.target.world();
}
@Override
public boolean isOnline() {
return this.target.isOnline();
}
@Override
public boolean isSpectator() {
return false;
}
@Override
public double scale() {
return this.target.scale();
}
@Override
public boolean isCrouching() {
return false;
}
@Override
public long playerTime() {
return this.target.playerTime();
}
@Override
public boolean isFlying() {
return false;
}
@Override
public int remainingAir() {
return this.target.remainingAir();
}
@Override
public Set<Integer> passengers() {
return Set.of();
}
@Override
public boolean isInitialized() {
return false;
}
@Override
public String name() {
return this.target.name();
}
@Override
public UUID uuid() {
return this.target.uuid();
}
@Override
public Object player() {
return this.target.player();
}
@Override
public String currentNameplate() {
return this.target.currentNameplate();
}
@Override
public String currentBubble() {
return this.target.currentBubble();
}
}
@@ -24,30 +24,51 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* MainTask is a periodic task that handles various operations related to the plugin, such as refreshing conditions,
* managing placeholders, and monitoring performance. It runs periodically and executes different plugin managers
* in each cycle to maintain the smooth operation of the system.
*/
public class MainTask implements Runnable {
private static int RUN_TICKS = 0;
private static final Map<Integer, Integer> TIME_1 = new ConcurrentHashMap<>(2048);
private static final Map<Integer, Integer> TIME_2 = new ConcurrentHashMap<>(2048);
private static final Set<Integer> requestedSharedPlaceholders = Collections.synchronizedSet(new ObjectOpenHashSet<>());
private int timer;
private final CustomNameplates plugin;
private boolean state;
/**
* Constructs a new MainTask instance.
*
* @param plugin the plugin instance associated with this task
*/
public MainTask(CustomNameplates plugin) {
this.plugin = plugin;
}
/**
* Returns the total number of ticks the task has executed.
*
* @return the number of ticks
*/
public static int getTicks() {
return RUN_TICKS;
}
/**
* Checks if a shared placeholder request for the specified count ID has already been made.
*
* @param countId the ID to check
* @return true if the request has been made, false otherwise
*/
public static boolean hasRequested(int countId) {
return !requestedSharedPlaceholders.add(countId);
}
/**
* Resets the tick counter to 0.
*/
public static void reset() {
RUN_TICKS = 0;
}
@@ -82,6 +103,11 @@ public class MainTask implements Runnable {
}
}
/**
* Retrieves the performance profile of the task based on the execution time and load.
*
* @return a HealthyProfile object containing the performance statistics
*/
public static HealthyProfile getHealthyProfile() {
long total1 = TIME_1.values().stream().mapToLong(Integer::longValue).sum();
long total2 = TIME_2.values().stream().mapToLong(Integer::longValue).sum();
@@ -99,14 +125,23 @@ public class MainTask implements Runnable {
);
}
/**
* Represents the health profile of the task, including performance metrics such as load and execution times.
*/
public static class HealthyProfile {
private final double load;
private final long totalTimeNS;
private final int actionBarConditionNS;
private final int refreshPlaceholderNS;
/**
* Constructs a new HealthyProfile instance with the provided metrics.
*
* @param load the load factor based on execution time
* @param totalTimeNS the total time spent on the task, in nanoseconds
* @param actionBarConditionNS the average time spent on action bar conditions, in nanoseconds
* @param refreshPlaceholderNS the average time spent refreshing placeholders, in nanoseconds
*/
public HealthyProfile(
double load,
long totalTimeNS,
@@ -119,18 +154,38 @@ public class MainTask implements Runnable {
this.totalTimeNS = totalTimeNS;
}
/**
* Gets the average time spent on action bar condition checks, in nanoseconds.
*
* @return the action bar condition time in nanoseconds
*/
public int getActionBarConditionNS() {
return actionBarConditionNS;
}
/**
* Gets the average time spent refreshing placeholders, in nanoseconds.
*
* @return the placeholder refresh time in nanoseconds
*/
public int getRefreshPlaceholderNS() {
return refreshPlaceholderNS;
}
/**
* Gets the load factor based on the task's execution time.
*
* @return the load factor
*/
public double getLoad() {
return load;
}
/**
* Gets the total time spent on the task, in nanoseconds.
*
* @return the total execution time in nanoseconds
*/
public long getTotalTimeNS() {
return totalTimeNS;
}
@@ -18,9 +18,11 @@
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.feature.bossbar.BossBar;
import net.momirealms.customnameplates.api.feature.tag.NameTagConfig;
import net.momirealms.customnameplates.api.network.PacketEvent;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import net.momirealms.customnameplates.api.util.Alignment;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.List;
@@ -114,29 +116,30 @@ public interface Platform {
/**
* Creates packets to display text on a custom text display entity.
*
* @param entityID the entity ID
* @param uuid the entity UUID
* @param position the position of the text
* @param pitch the pitch of the entity
* @param yaw the yaw of the entity
* @param headYaw the head yaw of the entity
* @param interpolationDelay the interpolation delay
* @param transformationInterpolationDuration the transformation interpolation duration
* @param entityID the entity ID
* @param uuid the entity UUID
* @param position the position of the text
* @param pitch the pitch of the entity
* @param yaw the yaw of the entity
* @param headYaw the head yaw of the entity
* @param interpolationDelay the interpolation delay
* @param transformationInterpolationDuration the transformation interpolation duration
* @param positionRotationInterpolationDuration the position and rotation interpolation duration
* @param component the component containing the text
* @param backgroundColor the background color
* @param opacity the opacity of the text
* @param hasShadow whether the text has a shadow
* @param isSeeThrough whether the text is see-through
* @param useDefaultBackgroundColor whether the default background color is used
* @param alignment the alignment of the text
* @param viewRange the view range of the text
* @param shadowRadius the shadow radius
* @param shadowStrength the shadow strength
* @param scale the scale of the text
* @param translation the translation of the text
* @param lineWidth the width of the text line
* @param isCrouching whether the entity is crouching
* @param component the component containing the text
* @param backgroundColor the background color
* @param opacity the opacity of the text
* @param hasShadow whether the text has a shadow
* @param isSeeThrough whether the text is see-through
* @param useDefaultBackgroundColor whether the default background color is used
* @param alignment the alignment of the text
* @param billboard
* @param viewRange the view range of the text
* @param shadowRadius the shadow radius
* @param shadowStrength the shadow strength
* @param scale the scale of the text
* @param translation the translation of the text
* @param lineWidth the width of the text line
* @param isCrouching whether the entity is crouching
* @return a list of packets for creating the text display
*/
List<Object> createTextDisplayPacket(
@@ -145,9 +148,8 @@ public interface Platform {
int interpolationDelay, int transformationInterpolationDuration, int positionRotationInterpolationDuration,
Object component, int backgroundColor, byte opacity,
boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment,
float viewRange, float shadowRadius, float shadowStrength,
Vector3 scale, Vector3 translation, int lineWidth, boolean isCrouching
);
Billboard billboard, float viewRange, float shadowRadius, float shadowStrength,
Vector3 scale, Vector3 translation, int lineWidth, boolean isCrouching);
/**
* Creates a modifier for interpolation delay.
@@ -189,13 +191,7 @@ public interface Platform {
*/
Consumer<List<Object>> createTranslationModifier(Vector3 translation);
/**
* Creates a modifier to change the opacity of a text display.
*
* @param opacity the new opacity
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createOpacityModifier(byte opacity);
Consumer<List<Object>> createSneakModifier(boolean isSneaking, boolean seeThrough, NameTagConfig config);
/**
* Updates an existing text display entity with modifiers.
@@ -17,6 +17,15 @@
package net.momirealms.customnameplates.api.feature;
/**
* Interface representing an adaptive image with methods for generating image
* prefixes, suffixes, and the full image string based on specified parameters.
* <p>
* The implementation of this interface should define how the image is adapted
* based on the given margins and advance, which are used for layout and
* positioning purposes.
* </p>
*/
public interface AdaptiveImage {
/**
@@ -115,7 +115,7 @@ public class ConfiguredCharacter {
}
advance = (float) Math.round((i + 1) * scale) + 1f;
} catch (IOException e) {
throw new RuntimeException(e);
throw new RuntimeException("Failed to load " + imageFile.toPath(), e);
}
}
@@ -17,64 +17,241 @@
package net.momirealms.customnameplates.api.feature;
import java.util.HashMap;
/**
* Enum representing different font offsets used for handling character spacing and height.
* The offsets are categorized into positive and negative values, each corresponding to
* a specific advance (horizontal movement) and height (vertical movement).
*/
public enum OffsetFont {
/**
* Represents a font with a character value of '\uf800', horizontal advance of -1, and vertical height of -3.
*/
NEG_1('\uf800', -1, -3),
/**
* Represents a font with a character value of '\uf801', horizontal advance of -2, and vertical height of -4.
*/
NEG_2('\uf801', -2, -4),
/**
* Represents a font with a character value of '\uf802', horizontal advance of -3, and vertical height of -5.
*/
NEG_3('\uf802', -3, -5),
/**
* Represents a font with a character value of '\uf803', horizontal advance of -4, and vertical height of -6.
*/
NEG_4('\uf803', -4, -6),
/**
* Represents a font with a character value of '\uf804', horizontal advance of -5, and vertical height of -7.
*/
NEG_5('\uf804', -5, -7),
/**
* Represents a font with a character value of '\uf805', horizontal advance of -6, and vertical height of -8.
*/
NEG_6('\uf805', -6, -8),
/**
* Represents a font with a character value of '\uf806', horizontal advance of -7, and vertical height of -9.
*/
NEG_7('\uf806', -7, -9),
/**
* Represents a font with a character value of '\uf807', horizontal advance of -8, and vertical height of -10.
*/
NEG_8('\uf807', -8, -10),
/**
* Represents a font with a character value of '\uf808', horizontal advance of -9, and vertical height of -11.
*/
NEG_9('\uf808', -9, -11),
/**
* Represents a font with a character value of '\uf809', horizontal advance of -10, and vertical height of -12.
*/
NEG_10('\uf809', -10, -12),
/**
* Represents a font with a character value of '\uf80a', horizontal advance of -11, and vertical height of -13.
*/
NEG_11('\uf80a', -11, -13),
/**
* Represents a font with a character value of '\uf80b', horizontal advance of -12, and vertical height of -14.
*/
NEG_12('\uf80b', -12, -14),
/**
* Represents a font with a character value of '\uf80c', horizontal advance of -13, and vertical height of -15.
*/
NEG_13('\uf80c', -13, -15),
/**
* Represents a font with a character value of '\uf80d', horizontal advance of -14, and vertical height of -16.
*/
NEG_14('\uf80d', -14, -16),
/**
* Represents a font with a character value of '\uf80e', horizontal advance of -15, and vertical height of -17.
*/
NEG_15('\uf80e', -15, -17),
/**
* Represents a font with a character value of '\uf80f', horizontal advance of -16, and vertical height of -18.
*/
NEG_16('\uf80f', -16, -18),
/**
* Represents a font with a character value of '\uf810', horizontal advance of -24, and vertical height of -26.
*/
NEG_24('\uf810', -24, -26),
/**
* Represents a font with a character value of '\uf811', horizontal advance of -32, and vertical height of -34.
*/
NEG_32('\uf811', -32, -34),
/**
* Represents a font with a character value of '\uf812', horizontal advance of -48, and vertical height of -50.
*/
NEG_48('\uf812', -48, -50),
/**
* Represents a font with a character value of '\uf813', horizontal advance of -64, and vertical height of -66.
*/
NEG_64('\uf813', -64, -66),
/**
* Represents a font with a character value of '\uf814', horizontal advance of -128, and vertical height of -130.
*/
NEG_128('\uf814', -128, -130),
/**
* Represents a font with a character value of '\uf815', horizontal advance of -256, and vertical height of -258.
*/
NEG_256('\uf815', -256, -258),
/**
* Represents a font with a character value of '\uf830', horizontal advance of 1, and vertical height of -1.
*/
POS_1('\uf830', 1, -1),
/**
* Represents a font with a character value of '\uf831', horizontal advance of 2, and vertical height of 1.
*/
POS_2('\uf831', 2, 1),
/**
* Represents a font with a character value of '\uf832', horizontal advance of 3, and vertical height of 2.
*/
POS_3('\uf832', 3, 2),
/**
* Represents a font with a character value of '\uf833', horizontal advance of 4, and vertical height of 3.
*/
POS_4('\uf833', 4, 3),
/**
* Represents a font with a character value of '\uf834', horizontal advance of 5, and vertical height of 4.
*/
POS_5('\uf834', 5, 4),
/**
* Represents a font with a character value of '\uf835', horizontal advance of 6, and vertical height of 5.
*/
POS_6('\uf835', 6, 5),
/**
* Represents a font with a character value of '\uf836', horizontal advance of 7, and vertical height of 6.
*/
POS_7('\uf836', 7, 6),
/**
* Represents a font with a character value of '\uf837', horizontal advance of 8, and vertical height of 7.
*/
POS_8('\uf837', 8, 7),
/**
* Represents a font with a character value of '\uf838', horizontal advance of 9, and vertical height of 8.
*/
POS_9('\uf838', 9, 8),
/**
* Represents a font with a character value of '\uf839', horizontal advance of 10, and vertical height of 9.
*/
POS_10('\uf839', 10, 9),
/**
* Represents a font with a character value of '\uf83a', horizontal advance of 11, and vertical height of 10.
*/
POS_11('\uf83a', 11, 10),
/**
* Represents a font with a character value of '\uf83b', horizontal advance of 12, and vertical height of 11.
*/
POS_12('\uf83b', 12, 11),
/**
* Represents a font with a character value of '\uf83c', horizontal advance of 13, and vertical height of 12.
*/
POS_13('\uf83c', 13, 12),
/**
* Represents a font with a character value of '\uf83d', horizontal advance of 14, and vertical height of 13.
*/
POS_14('\uf83d', 14, 13),
/**
* Represents a font with a character value of '\uf83e', horizontal advance of 15, and vertical height of 14.
*/
POS_15('\uf83e', 15, 14),
/**
* Represents a font with a character value of '\uf83f', horizontal advance of 16, and vertical height of 15.
*/
POS_16('\uf83f', 16, 15),
/**
* Represents a font with a character value of '\uf840', horizontal advance of 24, and vertical height of 23.
*/
POS_24('\uf840', 24, 23),
/**
* Represents a font with a character value of '\uf841', horizontal advance of 32, and vertical height of 31.
*/
POS_32('\uf841', 32, 31),
/**
* Represents a font with a character value of '\uf842', horizontal advance of 48, and vertical height of 47.
*/
POS_48('\uf842', 48, 47),
/**
* Represents a font with a character value of '\uf843', horizontal advance of 64, and vertical height of 63.
*/
POS_64('\uf843', 64, 63),
/**
* Represents a font with a character value of '\uf844', horizontal advance of 128, and vertical height of 127.
*/
POS_128('\uf844', 128, 127),
/**
* Represents a font with a character value of '\uf845', horizontal advance of 256, and vertical height of 255.
*/
POS_256('\uf845', 256, 255);
private static final HashMap<Integer, OffsetFont> negFastLookup = new HashMap<>();
private static final HashMap<Integer, OffsetFont> posFastLookup = new HashMap<>();
private static final OffsetFont[] negFastLookup = new OffsetFont[17];
private static final OffsetFont[] posFastLookup = new OffsetFont[17];
static {
for (OffsetFont f : OffsetFont.values()) {
if (f.advance > 0) {
posFastLookup.put(f.advance, f);
} else {
negFastLookup.put(-f.advance, f);
if (f.advance > 0 && f.advance <= 16) {
posFastLookup[f.advance] = f;
} else if (f.advance < 0 && f.advance >= -16) {
negFastLookup[-f.advance] = f;
}
}
}
@@ -83,24 +260,53 @@ public enum OffsetFont {
private final int advance;
private final int height;
/**
* Constructor to initialize the OffsetFont with a specific character, advance, and height.
*
* @param character the character associated with the offset
* @param advance the horizontal movement (positive or negative)
* @param height the vertical movement (positive or negative)
*/
OffsetFont(char character, int advance, int height) {
this.character = character;
this.advance = advance;
this.height = height;
}
/**
* Gets the character associated with this offset font.
*
* @return the character of this offset font
*/
public char character() {
return this.character;
}
/**
* Gets the advance value for this offset font.
*
* @return the advance (horizontal movement) for this offset font
*/
public float advance() {
return this.advance;
}
/**
* Gets the height value for this offset font.
*
* @return the height (vertical movement) for this offset font
*/
public int height() {
return this.height;
}
/**
* Creates a string of offset characters based on the given offset value.
* The result depends on whether the offset is positive or negative.
*
* @param offset the offset value
* @return a string of offset characters
*/
public static String createOffsets(float offset) {
if (offset >= 0) {
return shortestPosChars(offset);
@@ -109,6 +315,13 @@ public enum OffsetFont {
}
}
/**
* Generates a string of the shortest possible negative offset characters
* that sum up to the given advance value.
*
* @param advance the negative advance value
* @return the shortest string of negative offset characters
*/
public static String shortestNegChars(float advance) {
int n = (int) Math.ceil(advance);
StringBuilder stringBuilder = new StringBuilder();
@@ -141,10 +354,17 @@ public enum OffsetFont {
n -= 16;
}
if (n == 0) return stringBuilder.toString();
stringBuilder.append(negFastLookup.get(n).character());
stringBuilder.append(negFastLookup[n].character());
return stringBuilder.toString();
}
/**
* Generates a string of the shortest possible positive offset characters
* that sum up to the given advance value.
*
* @param advance the positive advance value
* @return the shortest string of positive offset characters
*/
public static String shortestPosChars(float advance) {
int n = (int) Math.ceil(advance);
StringBuilder stringBuilder = new StringBuilder();
@@ -177,7 +397,7 @@ public enum OffsetFont {
n -= 16;
}
if (n == 0) return stringBuilder.toString();
stringBuilder.append(posFastLookup.get(n).character());
stringBuilder.append(posFastLookup[n].character());
return stringBuilder.toString();
}
}
@@ -29,22 +29,44 @@ import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
/**
* Represents a dynamically parsed text that can contain placeholders.
* The text is parsed at initialization and placeholders are replaced with corresponding values.
* This class provides functionality to manage placeholders and generate dynamic text for players.
*/
public class PreParsedDynamicText {
private final String text;
private final List<Function<CNPlayer, Function<CNPlayer, String>>> textFunctions = new ObjectArrayList<>();
private final Set<Placeholder> set = new ObjectOpenHashSet<>();
private boolean init = false;
/**
* Constructs a PreParsedDynamicText with the given text.
*
* @param text the original text containing placeholders to be parsed
* @throws NullPointerException if the provided text is null
*/
public PreParsedDynamicText(String text) {
this.text = Objects.requireNonNull(text);
}
/**
* Constructs a PreParsedDynamicText with the given text and initializes it (parses placeholders).
*
* @param text the original text containing placeholders to be parsed
* @param init flag indicating whether to initialize the text immediately
* @throws NullPointerException if the provided text is null
*/
public PreParsedDynamicText(String text, boolean init) {
this.text = Objects.requireNonNull(text);
if (init) init();
}
/**
* Initializes the PreParsedDynamicText by parsing the text for placeholders and creating
* corresponding functions for replacing the placeholders with values.
* This method is called automatically if the constructor is provided with `true` for the init flag.
*/
public void init() {
if (init) return;
init = true;
@@ -101,6 +123,13 @@ public class PreParsedDynamicText {
set.addAll(new ObjectArrayList<>(placeholders));
}
/**
* Creates a dynamic text based on the current pre-parsed text, tailored to the given player.
* This method uses the player's data to generate the final text.
*
* @param player the player for whom the dynamic text is being generated
* @return a DynamicText object containing the final text for the player
*/
public DynamicText fastCreate(CNPlayer player) {
List<Function<CNPlayer, String>> functions = new ObjectArrayList<>();
for (Function<CNPlayer, Function<CNPlayer, String>> textFunction : textFunctions) {
@@ -109,6 +138,11 @@ public class PreParsedDynamicText {
return new DynamicText(text, functions, set);
}
/**
* Returns a set of placeholders detected in the text.
*
* @return a set of placeholders used in the text
*/
public Set<Placeholder> placeholders() {
return set;
}
@@ -20,6 +20,9 @@ package net.momirealms.customnameplates.api.feature.actionbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
/**
* ActionBar Config
*/
public interface ActionBarConfig {
/**
@@ -22,13 +22,15 @@ import net.momirealms.customnameplates.api.requirement.Requirement;
import static java.util.Objects.requireNonNull;
/**
* Implementation of ActionBarConfig
*/
public class ActionBarConfigImpl implements ActionBarConfig {
private final String id;
private final Requirement[] requirements;
private final CarouselText[] carouselTexts;
public ActionBarConfigImpl(String id, Requirement[] requirements, CarouselText[] carouselTexts) {
private ActionBarConfigImpl(String id, Requirement[] requirements, CarouselText[] carouselTexts) {
this.id = requireNonNull(id);
this.requirements = requireNonNull(requirements);
this.carouselTexts = requireNonNull(carouselTexts);
@@ -49,8 +51,10 @@ public class ActionBarConfigImpl implements ActionBarConfig {
return carouselTexts;
}
/**
* Builder Implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] requirements;
private CarouselText[] carouselTexts;
@@ -21,6 +21,9 @@ import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
/**
* Interface representing a manager for handling ActionBars.
*/
public interface ActionBarManager extends Reloadable {
/**
@@ -25,6 +25,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* Interface that defines methods for managing and calculating text advance data,
*/
public interface AdvanceManager extends Reloadable {
/**
@@ -23,6 +23,9 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* Interface representing character font advance data.
*/
public interface CharacterFontAdvanceData {
/**
@@ -26,13 +26,22 @@ import java.util.function.Function;
import static java.util.Objects.requireNonNull;
/**
* Implementation of the CharacterFontAdvanceData interface.
*/
public class CharacterFontAdvanceDataImpl implements CharacterFontAdvanceData {
private final Map<Integer, Float> data;
private final String id;
private final Function<Map<String, Object>, List<JsonObject>> fontProviderFunction;
public CharacterFontAdvanceDataImpl(String id, Map<Integer, Float> data, Function<Map<String, Object>, List<JsonObject>> fontProviderFunction) {
/**
* Constructs a new instance of CharacterFontAdvanceDataImpl.
*
* @param id the unique identifier for this font advance data
* @param data a map of character code points and their corresponding advance values
* @param fontProviderFunction a function that generates font provider configurations
*/
private CharacterFontAdvanceDataImpl(String id, Map<Integer, Float> data, Function<Map<String, Object>, List<JsonObject>> fontProviderFunction) {
this.data = data;
this.id = requireNonNull(id);
this.fontProviderFunction = requireNonNull(fontProviderFunction);
@@ -63,8 +72,10 @@ public class CharacterFontAdvanceDataImpl implements CharacterFontAdvanceData {
return fontProviderFunction.apply(properties);
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private final Int2FloatOpenHashMap data = new Int2FloatOpenHashMap();
private String id;
private Function<Map<String, Object>, List<JsonObject>> fontProviderFunction = (stringObjectMap -> null);
@@ -24,14 +24,16 @@ import java.util.*;
import static java.util.Objects.requireNonNull;
/**
* Implementation of ConfigurableFontAdvanceData
*/
public class ConfigurableFontAdvanceDataImpl implements ConfigurableFontAdvanceData {
private final float defaultAdvance;
private final Map<Integer, Float> data = new Int2FloatOpenHashMap();
private final List<CharacterFontAdvanceData> parents = new ObjectArrayList<>();
private final String id;
public ConfigurableFontAdvanceDataImpl(String id, float defaultAdvance, HashMap<Integer, Float> customData, List<CharacterFontAdvanceData> parentFonts) {
private ConfigurableFontAdvanceDataImpl(String id, float defaultAdvance, HashMap<Integer, Float> customData, List<CharacterFontAdvanceData> parentFonts) {
this.id = requireNonNull(id);
this.defaultAdvance = defaultAdvance;
for (CharacterFontAdvanceData parent : parentFonts) {
@@ -71,8 +73,10 @@ public class ConfigurableFontAdvanceDataImpl implements ConfigurableFontAdvanceD
return id;
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private final HashMap<Integer, Float> customData = new HashMap<>();
private final List<CharacterFontAdvanceData> parents = new ArrayList<>();
private float defaultAdvance = 0;
@@ -22,101 +22,14 @@ import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
/**
* Implements the {@link Background} interface, representing the detailed configuration of a background.
*/
@SuppressWarnings("DuplicatedCode")
public class BackgroundImpl implements Background {
private final String id;
private final ConfiguredCharacter left;
private final ConfiguredCharacter width_1;
private final ConfiguredCharacter width_2;
private final ConfiguredCharacter width_4;
private final ConfiguredCharacter width_8;
private final ConfiguredCharacter width_16;
private final ConfiguredCharacter width_32;
private final ConfiguredCharacter width_64;
private final ConfiguredCharacter width_128;
private final ConfiguredCharacter right;
public BackgroundImpl(
String id,
ConfiguredCharacter left,
ConfiguredCharacter width_1,
ConfiguredCharacter width_2,
ConfiguredCharacter width_4,
ConfiguredCharacter width_8,
ConfiguredCharacter width_16,
ConfiguredCharacter width_32,
ConfiguredCharacter width_64,
ConfiguredCharacter width_128,
ConfiguredCharacter right
) {
this.id = id;
this.left = left;
this.width_1 = width_1;
this.width_2 = width_2;
this.width_4 = width_4;
this.width_8 = width_8;
this.width_16 = width_16;
this.width_32 = width_32;
this.width_64 = width_64;
this.width_128 = width_128;
this.right = right;
}
@Override
public String id() {
return id;
}
@Override
public ConfiguredCharacter left() {
return left;
}
@Override
public ConfiguredCharacter width_1() {
return width_1;
}
@Override
public ConfiguredCharacter width_2() {
return width_2;
}
@Override
public ConfiguredCharacter width_4() {
return width_4;
}
@Override
public ConfiguredCharacter width_8() {
return width_8;
}
@Override
public ConfiguredCharacter width_16() {
return width_16;
}
@Override
public ConfiguredCharacter width_32() {
return width_32;
}
@Override
public ConfiguredCharacter width_64() {
return width_64;
}
@Override
public ConfiguredCharacter width_128() {
return width_128;
}
@Override
public ConfiguredCharacter right() {
return right;
}
public record BackgroundImpl(String id, ConfiguredCharacter left, ConfiguredCharacter width_1,
ConfiguredCharacter width_2, ConfiguredCharacter width_4, ConfiguredCharacter width_8,
ConfiguredCharacter width_16, ConfiguredCharacter width_32, ConfiguredCharacter width_64,
ConfiguredCharacter width_128, ConfiguredCharacter right) implements Background {
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
@@ -239,8 +152,10 @@ public class BackgroundImpl implements Background {
return Objects.hashCode(id);
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private ConfiguredCharacter left;
private ConfiguredCharacter width_1;
@@ -22,6 +22,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Interface representing a manager for background configurations.
*/
public interface BackgroundManager extends Reloadable {
/**
@@ -19,6 +19,9 @@ package net.momirealms.customnameplates.api.feature.bossbar;
import java.util.UUID;
/**
* Represents a BossBar
*/
public interface BossBar {
/**
@@ -50,21 +53,74 @@ public interface BossBar {
*/
Overlay overlay();
/**
* Enum representing the different overlay styles for the BossBar.
* The overlay style determines how the bar is divided, either as a simple progress bar or as notches.
*/
enum Overlay {
/**
* The bar is displayed as a simple progress bar.
*/
PROGRESS,
/**
* The bar is divided into 6 notches.
*/
NOTCHED_6,
/**
* The bar is divided into 10 notches.
*/
NOTCHED_10,
/**
* The bar is divided into 12 notches.
*/
NOTCHED_12,
/**
* The bar is divided into 20 notches.
*/
NOTCHED_20
}
/**
* Enum representing the different colors for the BossBar.
*/
enum Color {
/**
* Blue color for the BossBar.
*/
BLUE,
/**
* Green color for the BossBar.
*/
GREEN,
/**
* Pink color for the BossBar.
*/
PINK,
/**
* Purple color for the BossBar.
*/
PURPLE,
/**
* Red color for the BossBar.
*/
RED,
/**
* White color for the BossBar.
*/
WHITE,
/**
* Yellow color for the BossBar.
*/
YELLOW
}
}
@@ -20,6 +20,9 @@ package net.momirealms.customnameplates.api.feature.bossbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
/**
* Interface for BossBarConfig
*/
public interface BossBarConfig {
/**
@@ -22,8 +22,10 @@ import net.momirealms.customnameplates.api.requirement.Requirement;
import static java.util.Objects.requireNonNull;
/**
* Implementation of BossBar Config
*/
public class BossBarConfigImpl implements BossBarConfig {
private final String id;
private final Requirement[] requirements;
private final CarouselText[] carouselTexts;
@@ -31,7 +33,18 @@ public class BossBarConfigImpl implements BossBarConfig {
private final BossBar.Color color;
private final float progress;
public BossBarConfigImpl(String id, Requirement[] requirements, CarouselText[] carouselTexts, BossBar.Overlay overlay, BossBar.Color color, float progress) {
/**
* Constructor for creating a new BossBarConfigImpl.
* Ensures that all fields are non-null and properly initialized.
*
* @param id the unique ID of the BossBar configuration
* @param requirements the requirements for the BossBar
* @param carouselTexts the carousel texts associated with the BossBar
* @param overlay the overlay style of the BossBar
* @param color the color of the BossBar
* @param progress the progress value of the BossBar (between 0.0 and 1.0)
*/
private BossBarConfigImpl(String id, Requirement[] requirements, CarouselText[] carouselTexts, BossBar.Overlay overlay, BossBar.Color color, float progress) {
this.id = requireNonNull(id);
this.requirements = requireNonNull(requirements);
this.carouselTexts = requireNonNull(carouselTexts);
@@ -70,8 +83,10 @@ public class BossBarConfigImpl implements BossBarConfig {
return progress;
}
/**
* Builder Implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] requirements;
private CarouselText[] carouselTexts;
@@ -19,6 +19,9 @@ package net.momirealms.customnameplates.api.feature.bossbar;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
/**
* Manager interface for handling BossBar configurations and their updates.
*/
public interface BossBarManager extends Reloadable {
/**
@@ -20,6 +20,9 @@ package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
/**
* Bubble
*/
public interface Bubble extends AdaptiveImage {
/**
@@ -17,8 +17,13 @@
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
/**
* Bubble configuration
*/
public interface BubbleConfig {
/**
@@ -28,6 +33,15 @@ public interface BubbleConfig {
*/
String id();
/**
* Returns the command suggestion of the Bubble configuration.
*
* @return the configuration ID
*/
default String commandSuggestion() {
return id();
}
/**
* Returns the background color of the Bubble text.
*
@@ -49,6 +63,20 @@ public interface BubbleConfig {
*/
int maxLines();
/**
* Returns if the bubble has shadow
*
* @return has shadow or not
*/
boolean hasShadow();
/**
* Returns the billboard
*
* @return billboard
*/
Billboard billboard();
/**
* Returns the bubbles used in this configuration.
*
@@ -61,14 +89,14 @@ public interface BubbleConfig {
*
* @return the text prefix
*/
String textPrefix();
PreParsedDynamicText textPrefix();
/**
* Returns the text suffix to be applied after the Bubble content.
*
* @return the text suffix
*/
String textSuffix();
PreParsedDynamicText textSuffix();
/**
* Returns the display name of the Bubble.
@@ -106,6 +134,14 @@ public interface BubbleConfig {
*/
Builder id(String id);
/**
* Sets the command suggestion for the BubbleConfig.
*
* @param suggestion the command suggestion
* @return the builder instance
*/
Builder commandSuggestion(String suggestion);
/**
* Sets the display name for the BubbleConfig.
*
@@ -170,6 +206,22 @@ public interface BubbleConfig {
*/
Builder scale(Vector3 scale);
/**
* Sets if the text has shadow
*
* @param hasShadow has shadow
* @return the builder instance
*/
Builder hasShadow(boolean hasShadow);
/**
* Sets the billboard
*
* @param billboard billboard
* @return the builder instance
*/
Builder billboard(Billboard billboard);
/**
* Builds and returns the configured BubbleConfig instance.
*
@@ -17,37 +17,69 @@
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.Optional;
import static java.util.Objects.requireNonNull;
/**
* Implementation of the BubbleConfig interface
*/
public class BubbleConfigImpl implements BubbleConfig {
private final String id;
private final String commandSuggestion;
private final int backgroundColor;
private final int lineWidth;
private final int maxLines;
private final Bubble[] bubbles;
private final String textPrefix;
private final String textSuffix;
private final PreParsedDynamicText textPrefix;
private final PreParsedDynamicText textSuffix;
private final String displayName;
private final Vector3 scale;
private final boolean hasShadow;
private final Billboard billboard;
public BubbleConfigImpl(String id, String displayName, int backgroundColor, int lineWidth, int maxLines, Bubble[] bubbles, String textPrefix, String textSuffix, Vector3 scale) {
/**
* Constructs a new BubbleConfigImpl.
*
* @param id the unique ID for the bubble configuration
* @param commandSuggestion the command suggestion for the bubble configuration
* @param displayName the name to be displayed for the bubble configuration
* @param backgroundColor the background color for the bubble (in integer format)
* @param lineWidth the line width for the bubble display
* @param maxLines the maximum number of lines that can be displayed in the bubble
* @param bubbles an array of Bubble objects representing the actual bubbles
* @param textPrefix a prefix that will be added before the text in the bubble
* @param textSuffix a suffix that will be added after the text in the bubble
* @param scale the scale of the bubble display (as a Vector3)
* @param hasShadow has shadow or not
*/
public BubbleConfigImpl(String id, String commandSuggestion, String displayName, int backgroundColor, int lineWidth, int maxLines, Bubble[] bubbles, String textPrefix, String textSuffix, Vector3 scale, boolean hasShadow, Billboard billboard) {
this.backgroundColor = backgroundColor;
this.lineWidth = lineWidth;
this.maxLines = maxLines;
this.id = id;
this.commandSuggestion = commandSuggestion;
this.bubbles = requireNonNull(bubbles);
this.textPrefix = requireNonNull(textPrefix);
this.textSuffix = requireNonNull(textSuffix);
this.textPrefix = new PreParsedDynamicText(requireNonNull(textPrefix), true);
this.textSuffix = new PreParsedDynamicText(requireNonNull(textSuffix), true);
this.displayName = requireNonNull(displayName);
this.scale = requireNonNull(scale);
this.hasShadow = hasShadow;
this.billboard = billboard;
}
@Override
public String id() {
return id;
return this.id;
}
@Override
public String commandSuggestion() {
return this.commandSuggestion;
}
@Override
@@ -71,12 +103,12 @@ public class BubbleConfigImpl implements BubbleConfig {
}
@Override
public String textPrefix() {
public PreParsedDynamicText textPrefix() {
return textPrefix;
}
@Override
public String textSuffix() {
public PreParsedDynamicText textSuffix() {
return textSuffix;
}
@@ -90,8 +122,20 @@ public class BubbleConfigImpl implements BubbleConfig {
return scale;
}
public static class BuilderImpl implements Builder {
@Override
public boolean hasShadow() {
return hasShadow;
}
@Override
public Billboard billboard() {
return billboard;
}
/**
* Builder implementation for creating BubbleConfigImpl instances.
*/
public static class BuilderImpl implements Builder {
private int backgroundColor;
private int lineWidth;
private int maxLines;
@@ -99,8 +143,11 @@ public class BubbleConfigImpl implements BubbleConfig {
private String textPrefix;
private String textSuffix;
private String id;
private String commandSuggestion;
private String displayName;
private Vector3 scale;
private boolean hasShadow;
private Billboard billboard;
@Override
public Builder id(String id) {
@@ -114,6 +161,12 @@ public class BubbleConfigImpl implements BubbleConfig {
return this;
}
@Override
public Builder commandSuggestion(String commandSuggestion) {
this.commandSuggestion = commandSuggestion;
return this;
}
@Override
public Builder backgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
@@ -156,9 +209,21 @@ public class BubbleConfigImpl implements BubbleConfig {
return this;
}
@Override
public Builder hasShadow(boolean hasShadow) {
this.hasShadow = hasShadow;
return this;
}
@Override
public Builder billboard(Billboard billboard) {
this.billboard = billboard;
return this;
}
@Override
public BubbleConfig build() {
return new BubbleConfigImpl(id, displayName, backgroundColor, lineWidth, maxLines, bubbles, textPrefix, textSuffix, scale);
return new BubbleConfigImpl(id, Optional.ofNullable(this.commandSuggestion).orElse(id), displayName, backgroundColor, lineWidth, maxLines, bubbles, textPrefix, textSuffix, scale, hasShadow, billboard);
}
}
}
@@ -22,14 +22,25 @@ import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
/**
* Implementation of the Bubble interface
*/
public class BubbleImpl implements Bubble {
private final String id;
private final ConfiguredCharacter left;
private final ConfiguredCharacter right;
private final ConfiguredCharacter middle;
private final ConfiguredCharacter tail;
/**
* Constructs a new BubbleImpl.
*
* @param id the unique ID for the bubble
* @param left the character representing the left part of the bubble
* @param right the character representing the right part of the bubble
* @param middle the character representing the middle part of the bubble
* @param tail the character representing the tail part of the bubble
*/
public BubbleImpl(String id, ConfiguredCharacter left, ConfiguredCharacter right, ConfiguredCharacter middle, ConfiguredCharacter tail) {
this.id = id;
this.left = left;
@@ -149,8 +160,10 @@ public class BubbleImpl implements Bubble {
return sb.toString();
}
/**
* Builder implementation for creating BubbleImpl instances.
*/
public static class BuilderImpl implements Builder {
private String id;
private ConfiguredCharacter left;
private ConfiguredCharacter right;
@@ -25,6 +25,10 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
/**
* The BubbleManager interface is responsible for managing the configuration and display of Bubbles,
* including retrieving available Bubbles, managing Bubble configurations, and controlling display settings.
*/
public interface BubbleManager extends Reloadable {
/**
@@ -59,6 +63,14 @@ public interface BubbleManager extends Reloadable {
@Nullable
BubbleConfig bubbleConfigById(String id);
/**
* Retrieves a Bubble configuration by its command suggestion
*
* @param suggestion command suggestion
* @return the BubbleConfig instance, or null if not found
*/
@Nullable BubbleConfig bubbleConfigByCommand(String suggestion);
/**
* Checks if a player has access to a specific Bubble by its ID.
*
@@ -17,9 +17,21 @@
package net.momirealms.customnameplates.api.feature.bubble;
/**
* Enum representing the different modes for Bubble channels.
* The mode determines the visibility and access rules for Bubbles in various channels.
*/
public enum ChannelMode {
/**
* The ALL mode means that Bubbles can be displayed in all channels, regardless of the player's status or permissions.
*/
ALL,
/**
* The JOINED mode means that Bubbles can only be displayed in channels where the player is currently a member.
*/
JOINED,
/**
* The CAN_JOIN mode means that Bubbles can be displayed in channels that the player can join, even if they are not currently in them.
*/
CAN_JOIN
}
}
@@ -24,8 +24,13 @@ import net.momirealms.customnameplates.api.CustomNameplates;
* for managing the plugin and chat manager.
*/
public abstract class AbstractChatMessageProvider implements ChatMessageProvider {
/**
* The CustomNameplates plugin
*/
protected CustomNameplates plugin;
/**
* The chat manager
*/
protected ChatManager manager;
/**
@@ -26,6 +26,8 @@ import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
*/
public interface ChatManager extends Reloadable {
String replaceEmojis(CNPlayer player, String text);
/**
* Sets a custom chat message provider.
*
@@ -17,5 +17,8 @@
package net.momirealms.customnameplates.api.feature.image;
/**
* A record representing an animation with a speed and a number of frames.
*/
public record Animation(int speed, int frames) {
}
@@ -20,6 +20,9 @@ package net.momirealms.customnameplates.api.feature.image;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import org.jetbrains.annotations.Nullable;
/**
* An interface represents the image
*/
public interface Image {
/**
@@ -22,14 +22,16 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* Implementation of Image
*/
public class ImageImpl implements Image {
private final String id;
private final boolean removeShadow;
private final ConfiguredCharacter character;
private final Animation animation;
public ImageImpl(String id, boolean removeShadow, Animation animation, ConfiguredCharacter character) {
private ImageImpl(String id, boolean removeShadow, Animation animation, ConfiguredCharacter character) {
this.id = id;
this.removeShadow = removeShadow;
this.character = character;
@@ -69,8 +71,10 @@ public class ImageImpl implements Image {
return Objects.hashCode(id);
}
/**
* The builder Implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private boolean removeShadow;
private ConfiguredCharacter character;
@@ -22,6 +22,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Manages image configurations
*/
public interface ImageManager extends Reloadable {
/**
@@ -20,6 +20,9 @@ package net.momirealms.customnameplates.api.feature.nameplate;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
/**
* Nameplate
*/
public interface Nameplate extends AdaptiveImage {
/**
@@ -29,6 +32,15 @@ public interface Nameplate extends AdaptiveImage {
*/
String id();
/**
* Returns the command suggestion of the nameplate configuration.
*
* @return the nameplate ID
*/
default String commandSuggestion() {
return id();
}
/**
* Returns the display name of the nameplate.
*
@@ -86,6 +98,14 @@ public interface Nameplate extends AdaptiveImage {
*/
Builder id(String id);
/**
* Sets the command suggestion for the nameplate
*
* @param commandSuggestion command suggestion
* @return the builder instance
*/
Builder commandSuggestion(String commandSuggestion);
/**
* Sets the display name for the nameplate.
*
@@ -21,18 +21,23 @@ import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
import java.util.Optional;
/**
* Implementation of Nameplate
*/
public class NameplateImpl implements Nameplate {
private final String id;
private final String commandSuggestion;
private final String displayName;
private final ConfiguredCharacter left;
private final ConfiguredCharacter middle;
private final ConfiguredCharacter right;
private final int minWidth;
public NameplateImpl(String id, String displayName, int minWidth, ConfiguredCharacter left, ConfiguredCharacter middle, ConfiguredCharacter right) {
private NameplateImpl(String id, String commandSuggestion, String displayName, int minWidth, ConfiguredCharacter left, ConfiguredCharacter middle, ConfiguredCharacter right) {
this.id = id;
this.commandSuggestion = commandSuggestion;
this.displayName = displayName;
this.minWidth = minWidth;
this.left = left;
@@ -50,6 +55,11 @@ public class NameplateImpl implements Nameplate {
return displayName;
}
@Override
public String commandSuggestion() {
return this.commandSuggestion;
}
@Override
public ConfiguredCharacter left() {
return left;
@@ -134,9 +144,12 @@ public class NameplateImpl implements Nameplate {
return sb.toString();
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private String commandSuggestion;
private String displayName;
private ConfiguredCharacter left;
private ConfiguredCharacter middle;
@@ -149,6 +162,12 @@ public class NameplateImpl implements Nameplate {
return this;
}
@Override
public Builder commandSuggestion(String commandSuggestion) {
this.commandSuggestion = commandSuggestion;
return this;
}
@Override
public Builder displayName(String displayName) {
this.displayName = displayName;
@@ -181,7 +200,7 @@ public class NameplateImpl implements Nameplate {
@Override
public Nameplate build() {
return new NameplateImpl(id, displayName, minWidth, left, middle, right);
return new NameplateImpl(id, Optional.ofNullable(commandSuggestion).orElse(id), displayName, minWidth, left, middle, right);
}
}
}
@@ -23,6 +23,10 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Manages the nameplates system, providing functionality to retrieve, check access,
* and manipulate nameplates associated with players.
*/
public interface NameplateManager extends Reloadable {
/**
@@ -34,6 +38,15 @@ public interface NameplateManager extends Reloadable {
@Nullable
Nameplate nameplateById(String id);
/**
* Retrieves a Nameplate by command suggestion.
*
* @param suggestion the command suggestion of the nameplate
* @return the Nameplate instance, or null if not found
*/
@Nullable
Nameplate nameplateByCommand(String suggestion);
/**
* Returns a collection of all available nameplates.
*
@@ -19,6 +19,9 @@ package net.momirealms.customnameplates.api.feature.pack;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
/**
* Interface to manager resource packs
*/
public interface ResourcePackManager extends Reloadable {
/**
@@ -28,23 +28,63 @@ import java.util.UUID;
import java.util.Vector;
import java.util.function.Consumer;
/**
* Represents an abstract tag for a {@link CNPlayer} that can be shown to specific viewers.
* This class handles the rendering of the tag, showing and hiding it for specific players,
* and managing tag attributes such as opacity and scale.
*/
public abstract class AbstractTag implements Tag {
/**
* The owner of this tag
*/
protected CNPlayer owner;
/**
* The {@link TagRenderer} responsible for rendering this tag.
*/
protected TagRenderer renderer;
/**
* The unique UUID assigned to this tag.
*/
protected final UUID uuid = UUID.randomUUID();
/**
* The unique entity ID assigned to this tag, used to track visibility and actions.
*/
protected final int entityID = SelfIncreaseEntityID.getAndIncrease();
/**
* A flag indicating whether the tag is currently visible to viewers.
*/
protected boolean isShown = false;
/**
* A list of players who are currently viewing this tag.
*/
protected final Vector<CNPlayer> viewers = new Vector<>();
/**
* An array representation of the viewers, used for optimization.
*/
protected CNPlayer[] viewerArray = new CNPlayer[0];
public AbstractTag(CNPlayer owner, TagRenderer renderer) {
/**
* Constructs a new {@link AbstractTag} for the given {@link CNPlayer} owner and
* {@link TagRenderer}.
*
* @param owner the {@link CNPlayer} who owns this tag
* @param renderer the {@link TagRenderer} used to render this tag
*/
protected AbstractTag(CNPlayer owner, TagRenderer renderer) {
this.owner = owner;
this.renderer = renderer;
}
public CNPlayer[] viewerArray() {
return this.viewerArray;
}
/**
* Spawns the tag for the given viewer by sending a packet to the viewer.
*
* @param viewer the {@link CNPlayer} who will see the tag
* @return a list of objects representing the spawn packet for the tag
*/
protected abstract List<Object> spawnPacket(CNPlayer viewer);
@Override
@@ -126,13 +166,6 @@ public abstract class AbstractTag implements Tag {
}
}
@Override
public void darkTag(CNPlayer viewer, boolean dark) {
Consumer<List<Object>> modifiers = CustomNameplates.getInstance().getPlatform().createOpacityModifier(dark ? 64 : opacity());
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifiers));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
@Override
public void onPlayerScaleUpdate(double scale) {
for (CNPlayer viewer : viewerArray) {
@@ -188,6 +221,9 @@ public abstract class AbstractTag implements Tag {
return uuid;
}
/**
* Resets the viewer array
*/
protected void resetViewerArray() {
this.viewerArray = viewers.toArray(new CNPlayer[0]);
}
@@ -20,8 +20,13 @@ package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.util.Alignment;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import net.momirealms.customnameplates.common.util.Tristate;
/**
* NameTag Configuration
*/
public interface NameTagConfig {
/**
@@ -73,12 +78,18 @@ public interface NameTagConfig {
*/
boolean hasShadow();
/**
* Gets the billboard
*
* @return billboard
*/
Billboard billboard();
/**
* Checks if the name tag is see-through.
*
* @return true if the name tag is see-through, false otherwise
*/
boolean isSeeThrough();
Tristate isSeeThrough();
/**
* Checks if the default background color is used.
@@ -241,7 +252,7 @@ public interface NameTagConfig {
* @param seeThrough true if the name tag is see-through, false otherwise
* @return the builder instance
*/
Builder seeThrough(boolean seeThrough);
Builder seeThrough(Tristate seeThrough);
/**
* Sets whether the name tag uses the default background color.
@@ -259,6 +270,14 @@ public interface NameTagConfig {
*/
Builder alignment(Alignment alignment);
/**
* Sets the billboard of the name tag
*
* @param billboard billboard
* @return the builder instance
*/
Builder billboard(Billboard billboard);
/**
* Sets the view range for the name tag.
*
@@ -20,10 +20,14 @@ package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.util.Alignment;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import net.momirealms.customnameplates.common.util.Tristate;
/**
* Implementation of NameTagConfig
*/
public class NameTagConfigImpl implements NameTagConfig {
private final String id;
private final Requirement[] ownerRequirements;
private final Requirement[] viewerRequirements;
@@ -32,9 +36,10 @@ public class NameTagConfigImpl implements NameTagConfig {
private final byte opacity;
private final int backgroundColor;
private final boolean hasShadow;
private final boolean isSeeThrough;
private final Tristate isSeeThrough;
private final boolean useDefaultBackgroundColor;
private final Alignment alignment;
private final Billboard billboard;
private final float viewRange;
private final float shadowRadius;
private final float shadowStrength;
@@ -44,7 +49,7 @@ public class NameTagConfigImpl implements NameTagConfig {
private final boolean affectedByScale;
private final boolean affectedBySpectator;
public NameTagConfigImpl(String id, Requirement[] ownerRequirements, Requirement[] viewerRequirements, CarouselText[] carouselTexts, int lineWidth, byte opacity, int backgroundColor, boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment, float viewRange, float shadowRadius, float shadowStrength, Vector3 scale, Vector3 translation, boolean affectedByCrouching, boolean affectedByScale, boolean affectedBySpectator) {
private NameTagConfigImpl(String id, Requirement[] ownerRequirements, Requirement[] viewerRequirements, CarouselText[] carouselTexts, int lineWidth, byte opacity, int backgroundColor, boolean hasShadow, Tristate isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment, Billboard billboard, float viewRange, float shadowRadius, float shadowStrength, Vector3 scale, Vector3 translation, boolean affectedByCrouching, boolean affectedByScale, boolean affectedBySpectator) {
this.id = id;
this.ownerRequirements = ownerRequirements;
this.viewerRequirements = viewerRequirements;
@@ -55,6 +60,7 @@ public class NameTagConfigImpl implements NameTagConfig {
this.isSeeThrough = isSeeThrough;
this.useDefaultBackgroundColor = useDefaultBackgroundColor;
this.alignment = alignment;
this.billboard = billboard;
this.viewRange = viewRange;
this.shadowRadius = shadowRadius;
this.shadowStrength = shadowStrength;
@@ -102,7 +108,12 @@ public class NameTagConfigImpl implements NameTagConfig {
}
@Override
public boolean isSeeThrough() {
public Billboard billboard() {
return billboard;
}
@Override
public Tristate isSeeThrough() {
return isSeeThrough;
}
@@ -161,6 +172,9 @@ public class NameTagConfigImpl implements NameTagConfig {
return lineWidth;
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] ownerRequirements;
@@ -170,9 +184,10 @@ public class NameTagConfigImpl implements NameTagConfig {
private byte opacity;
private int backgroundColor;
private boolean hasShadow;
private boolean isSeeThrough;
private Tristate isSeeThrough;
private boolean useDefaultBackgroundColor;
private Alignment alignment;
private Billboard billboard;
private float viewRange;
private float shadowRadius;
private float shadowStrength;
@@ -231,7 +246,7 @@ public class NameTagConfigImpl implements NameTagConfig {
}
@Override
public Builder seeThrough(boolean seeThrough) {
public Builder seeThrough(Tristate seeThrough) {
this.isSeeThrough = seeThrough;
return this;
}
@@ -248,6 +263,12 @@ public class NameTagConfigImpl implements NameTagConfig {
return this;
}
@Override
public Builder billboard(Billboard billboard) {
this.billboard = billboard;
return this;
}
@Override
public Builder viewRange(float viewRange) {
this.viewRange = viewRange;
@@ -298,7 +319,7 @@ public class NameTagConfigImpl implements NameTagConfig {
@Override
public NameTagConfig build() {
return new NameTagConfigImpl(id, ownerRequirements, viewerRequirements, carouselTexts, lineWidth, opacity, backgroundColor, hasShadow, isSeeThrough, useDefaultBackgroundColor, alignment, viewRange, shadowRadius, shadowStrength, scale, translation, affectedByCrouching, affectedByScale, affectedBySpectator);
return new NameTagConfigImpl(id, ownerRequirements, viewerRequirements, carouselTexts, lineWidth, opacity, backgroundColor, hasShadow, isSeeThrough, useDefaultBackgroundColor, alignment, billboard, viewRange, shadowRadius, shadowStrength, scale, translation, affectedByCrouching, affectedByScale, affectedBySpectator);
}
}
}
@@ -22,6 +22,9 @@ import net.momirealms.customnameplates.api.util.Vector3;
import java.util.UUID;
/**
* Represents a tag
*/
public interface Tag {
/**
@@ -59,6 +62,11 @@ public interface Tag {
*/
boolean affectedByScaling();
/**
* Checks if the tag is affected by spectator mode.
*
* @return true if affected by spectator mode, false otherwise
*/
boolean affectedBySpectator();
/**
@@ -189,6 +197,8 @@ public interface Tag {
/**
* Updates the translation of the tag for a certain player
*
* @param viewer the player to update
*/
void updateTranslation(CNPlayer viewer);
@@ -19,6 +19,9 @@ package net.momirealms.customnameplates.api.feature.tag;
import java.util.function.Predicate;
/**
* An interface to control the rendering of tags
*/
public interface TagRenderer {
/**
@@ -25,19 +25,49 @@ import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Represents a view of teams and their associated members.
* <p>
* This class allows you to manage a collection of teams, with each team having a set of member names.
* You can add or remove members from teams, retrieve the list of members for a specific team,
* or remove entire teams.
* </p>
*/
public class TeamView {
/**
* A map that stores the team names as keys and their associated members as values.
* The members are stored as a set of strings to avoid duplicates.
*/
private final Map<String, Set<String>> teamMembers = new Object2ObjectOpenHashMap<>();
/**
* Retrieves the members of a given team.
*
* @param team the name of the team
* @return a set of member names, or {@code null} if the team does not exist
*/
@Nullable
public Set<String> getTeamMembers(String team) {
return teamMembers.get(team);
}
/**
* Adds a collection of members to a team. If the team does not exist, it will be created.
*
* @param team the name of the team
* @param members the collection of members to add
*/
public void addTeamMembers(String team, Collection<String> members) {
teamMembers.computeIfAbsent(team, k -> new ObjectOpenHashSet<>(members));
}
/**
* Removes a collection of members from a team. If the team exists, the members will be removed
* from the team's member set.
*
* @param team the name of the team
* @param members the collection of members to remove
*/
public void removeTeamMembers(String team, Collection<String> members) {
Set<String> membersSet = teamMembers.get(team);
if (membersSet != null) {
@@ -45,6 +75,11 @@ public class TeamView {
}
}
/**
* Removes an entire team and all its members.
*
* @param team the name of the team to remove
*/
public void removeTeam(String team) {
this.teamMembers.remove(team);
}
@@ -18,11 +18,15 @@
package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.feature.JoinQuitListener;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public interface UnlimitedTagManager extends Reloadable {
/**
* An interface manages unlimited tags
*/
public interface UnlimitedTagManager extends Reloadable, JoinQuitListener {
/**
* Called every tick to update the state of tags.
@@ -23,6 +23,8 @@ import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.json.JSONOptions;
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
import net.momirealms.customnameplates.api.ConfigManager;
import net.momirealms.customnameplates.api.CustomNameplates;
@@ -35,10 +37,14 @@ import java.util.concurrent.TimeUnit;
*/
public class AdventureHelper {
/**
* Whether to enable legacy color code support
*/
public static boolean legacySupport = false;
private final MiniMessage miniMessage;
private final MiniMessage miniMessageStrict;
private final GsonComponentSerializer gsonComponentSerializer;
public static boolean legacySupport = false;
private final Cache<String, Component> miniMessageToComponentCache;
private final Cache<String, Object> miniMessageToMinecraftComponentCache;
@@ -48,7 +54,19 @@ public class AdventureHelper {
private AdventureHelper() {
this.miniMessage = MiniMessage.builder().build();
this.miniMessageStrict = MiniMessage.builder().strict(true).build();
this.gsonComponentSerializer = GsonComponentSerializer.builder().build();
GsonComponentSerializer.Builder builder = GsonComponentSerializer.builder();
if (!VersionHelper.isVersionNewerThan1_20_5()) {
builder.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get());
builder.editOptions((b) -> b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, false));
}
if (!VersionHelper.isVersionNewerThan1_21_5()) {
builder.editOptions((b) -> {
b.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE);
b.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE);
b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true);
});
}
this.gsonComponentSerializer = builder.build();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, r -> {
Thread thread = Executors.defaultThreadFactory().newThread(r);
@@ -84,6 +102,9 @@ public class AdventureHelper {
.build();
}
/**
* Clear cache
*/
public static void clearCache() {
AdventureHelper instance = getInstance();
instance.miniMessageToMinecraftComponentCache.cleanUp();
@@ -217,8 +238,14 @@ public class AdventureHelper {
return "<#FFFEFD>" + text + "</#FFFEFD>";
}
/**
* Removes shadow from the provided text using a specific color code.
*
* @param text the text to modify
* @return the text wrapped in a color tag to remove shadows
*/
public static String removeShadow(String text) {
return "<#F0F0F0>" + text + "</#F0F0F0>";
return "<shadow:#00000000><#F0F0F0>" + text + "</#F0F0F0></shadow>";
}
/**
@@ -293,19 +320,19 @@ public class AdventureHelper {
case '7' -> stringBuilder.append("<gray>");
case '8' -> stringBuilder.append("<dark_gray>");
case '9' -> stringBuilder.append("<blue>");
case 'a' -> stringBuilder.append("<green>");
case 'b' -> stringBuilder.append("<aqua>");
case 'c' -> stringBuilder.append("<red>");
case 'd' -> stringBuilder.append("<light_purple>");
case 'e' -> stringBuilder.append("<yellow>");
case 'f' -> stringBuilder.append("<white>");
case 'r' -> stringBuilder.append("<reset>");
case 'l' -> stringBuilder.append("<b>");
case 'm' -> stringBuilder.append("<st>");
case 'o' -> stringBuilder.append("<i>");
case 'n' -> stringBuilder.append("<u>");
case 'k' -> stringBuilder.append("<obf>");
case 'x' -> {
case 'a', 'A' -> stringBuilder.append("<green>");
case 'b', 'B' -> stringBuilder.append("<aqua>");
case 'c', 'C' -> stringBuilder.append("<red>");
case 'd', 'D' -> stringBuilder.append("<light_purple>");
case 'e', 'E' -> stringBuilder.append("<yellow>");
case 'f', 'F' -> stringBuilder.append("<white>");
case 'r', 'R' -> stringBuilder.append("<reset>");
case 'l', 'L' -> stringBuilder.append("<b>");
case 'm', 'M' -> stringBuilder.append("<st>");
case 'o', 'O' -> stringBuilder.append("<i>");
case 'n', 'N' -> stringBuilder.append("<u>");
case 'k', 'K' -> stringBuilder.append("<obf>");
case 'x', 'X' -> {
if (i + 13 >= chars.length
|| !isLegacyColorCode(chars[i+2])
|| !isLegacyColorCode(chars[i+4])
@@ -327,6 +354,28 @@ public class AdventureHelper {
.append(">");
i += 12;
}
case '#' -> {
if (i + 7 >= chars.length
|| !isHexColorCode(chars[i+2])
|| !isHexColorCode(chars[i+3])
|| !isHexColorCode(chars[i+4])
|| !isHexColorCode(chars[i+5])
|| !isHexColorCode(chars[i+6])
|| !isHexColorCode(chars[i+7])) {
stringBuilder.append(chars[i]);
continue;
}
stringBuilder
.append("<#")
.append(chars[i+2])
.append(chars[i+3])
.append(chars[i+4])
.append(chars[i+5])
.append(chars[i+6])
.append(chars[i+7])
.append(">");
i += 6;
}
default -> {
stringBuilder.append(chars[i]);
continue;
@@ -336,4 +385,10 @@ public class AdventureHelper {
}
return stringBuilder.toString();
}
private static boolean isHexColorCode(char c) {
return c >= '0' && c <= '9' ||
c >= 'a' && c <= 'f' ||
c >= 'A' && c <= 'F';
}
}
@@ -27,6 +27,9 @@ public class GsonHelper {
private final Gson gson;
/**
* Create the gson
*/
public GsonHelper() {
this.gson = new GsonBuilder()
.create();
@@ -28,11 +28,14 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* This class implements the VersionManager interface and is responsible for managing version-related information.
* VersionHelper is a utility class that provides methods for managing and checking version-related information,
* including plugin updates and server version details. It implements the VersionManager interface.
*/
public class VersionHelper {
// Method to asynchronously check for plugin updates
/**
* A function to check for plugin updates asynchronously by comparing the plugin's current version with the latest version available.
*/
public static final Function<NameplatesPlugin, CompletableFuture<Boolean>> UPDATE_CHECKER = (plugin) -> {
CompletableFuture<Boolean> updateFuture = new CompletableFuture<>();
plugin.getScheduler().async().execute(() -> {
@@ -58,15 +61,20 @@ public class VersionHelper {
return updateFuture;
};
private static float version;
private static int version;
private static boolean mojmap;
private static boolean folia;
private static boolean mohist;
private static boolean paper;
/**
* Initializes version-specific settings based on the server version.
* This method checks if the server is running Mojmap, Folia, Mohist, or Paper.
*
* @param serverVersion The server version string.
*/
public static void init(String serverVersion) {
String[] split = serverVersion.split("\\.");
version = Float.parseFloat(split[1] + "." + (split.length == 3 ? split[2] : "0"));
version = parseVersionToInteger(serverVersion);
checkMojMap();
checkFolia();
checkMohist();
@@ -75,12 +83,58 @@ public class VersionHelper {
paper = paper && !isModdedServer;
}
public static int parseVersionToInteger(String versionString) {
int v1 = 0;
int v2 = 0;
int v3 = 0;
int currentNumber = 0;
int part = 0;
for(int i = 0; i < versionString.length(); ++i) {
char c = versionString.charAt(i);
if (c >= '0' && c <= '9') {
currentNumber = currentNumber * 10 + (c - 48);
} else if (c == '.') {
if (part == 0) {
v1 = currentNumber;
}
if (part == 1) {
v2 = currentNumber;
}
++part;
currentNumber = 0;
if (part > 2) {
break;
}
}
}
if (part == 0) {
v1 = currentNumber;
} else if (part == 1) {
v2 = currentNumber;
} else if (part == 2) {
v3 = currentNumber;
}
return 10000 * v1 + v2 * 100 + v3;
}
/**
* Gets the current server version as a float.
*
* @return The server version as a float.
*/
public static float version() {
return version;
}
/**
* Checks if the server is running Mojmap.
*/
private static void checkMojMap() {
// Check if the server is Mojmap
try {
Class.forName("net.minecraft.network.protocol.game.ClientboundBossEventPacket");
mojmap = true;
@@ -88,6 +142,9 @@ public class VersionHelper {
}
}
/**
* Checks if the server is running Folia.
*/
private static void checkFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
@@ -96,6 +153,9 @@ public class VersionHelper {
}
}
/**
* Checks if the server is running Mohist.
*/
private static void checkMohist() {
try {
Class.forName("com.mohistmc.api.ServerAPI");
@@ -104,6 +164,9 @@ public class VersionHelper {
}
}
/**
* Checks if the server is running Paper or its forks.
*/
private static void checkPaper() {
try {
Class.forName("com.destroystokyo.paper.Metrics");
@@ -112,47 +175,134 @@ public class VersionHelper {
}
}
public static boolean isVersionNewerThan26_1() {
return version >= 260100;
}
/**
* Checks if the server version is newer than 1.21.9
*
* @return True if the version is newer than 1.21.9, otherwise false.
*/
public static boolean isVersionNewerThan1_21_9() {
return version >= 12109;
}
/**
* Checks if the server version is newer than 1.21.5
*
* @return True if the version is newer than 1.21.5, otherwise false.
*/
public static boolean isVersionNewerThan1_21_5() {
return version >= 12105;
}
/**
* Checks if the server version is newer than 1.21.4
*
* @return True if the version is newer than 1.21.4, otherwise false.
*/
public static boolean isVersionNewerThan1_21_4() {
return version >= 12104;
}
/**
* Checks if the server version is newer than 1.21.2.
*
* @return True if the version is newer than 1.21.2, otherwise false.
*/
public static boolean isVersionNewerThan1_21_2() {
return version >= 21.19;
return version >= 12102;
}
/**
* Checks if the server version is newer than 1.20.5.
*
* @return True if the version is newer than 1.20.5, otherwise false.
*/
public static boolean isVersionNewerThan1_20_5() {
return version >= 20.49;
return version >= 12005;
}
/**
* Checks if the server version is newer than 1.20.4.
*
* @return True if the version is newer than 1.20.4, otherwise false.
*/
public static boolean isVersionNewerThan1_20_4() {
return version >= 20.39;
return version >= 12004;
}
/**
* Checks if the server version is newer than 1.19.4.
*
* @return True if the version is newer than 1.19.4, otherwise false.
*/
public static boolean isVersionNewerThan1_19_4() {
return version >= 19.39;
return version >= 11904;
}
/**
* Checks if the server version is newer than 1.20.2.
*
* @return True if the version is newer than 1.20.2, otherwise false.
*/
public static boolean isVersionNewerThan1_20_2() {
return version >= 20.19;
return version >= 12002;
}
/**
* Checks if the server version is newer than 1.20.
*
* @return True if the version is newer than 1.20, otherwise false.
*/
public static boolean isVersionNewerThan1_20() {
return version >= 20;
return version >= 12000;
}
/**
* Checks if the server is running Folia.
*
* @return True if the server is running Folia, otherwise false.
*/
public static boolean isFolia() {
return folia;
}
/**
* Checks if the server is running Mohist.
*
* @return True if the server is running Mohist, otherwise false.
*/
public static boolean isMohist() {
return mohist;
}
/**
* Checks if the server is running Paper or its forks.
*
* @return True if the server is running Paper or its forks, otherwise false.
*/
public static boolean isPaperOrItsForks() {
return paper;
}
/**
* Checks if the server is using Mojmap.
*
* @return True if the server is using Mojmap, otherwise false.
*/
public static boolean isMojmap() {
return mojmap;
}
// Method to compare two version strings
/**
* Compares two version strings to determine if the first version is newer than the second.
*
* @param newV The new version string.
* @param currentV The current version string.
* @return True if the new version is newer than the current version, otherwise false.
*/
private static boolean compareVer(String newV, String currentV) {
if (newV == null || currentV == null || newV.isEmpty() || currentV.isEmpty()) {
return false;
@@ -170,31 +320,11 @@ public class VersionHelper {
return true;
} else if (newNum < currentNum) {
return false;
} else if (newPart.length > 1 && currentPart.length > 1) {
String[] newHotfix = newPart[1].split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
String[] currentHotfix = currentPart[1].split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
if (newHotfix.length == 2 && currentHotfix.length == 1) return true;
else if (newHotfix.length > 1 && currentHotfix.length > 1) {
int newHotfixNum = Integer.parseInt(newHotfix[1]);
int currentHotfixNum = Integer.parseInt(currentHotfix[1]);
if (newHotfixNum > currentHotfixNum) {
return true;
} else if (newHotfixNum < currentHotfixNum) {
return false;
} else {
return newHotfix[0].compareTo(currentHotfix[0]) > 0;
}
}
} else if (newPart.length > 1) {
return true;
} else if (currentPart.length > 1) {
return false;
}
}
catch (NumberFormatException ignored) {
return false;
} catch (NumberFormatException e) {
// handle error
}
}
return newVS.length > currentVS.length;
return false;
}
}
}
@@ -19,18 +19,12 @@ package net.momirealms.customnameplates.api.network;
import net.momirealms.customnameplates.common.event.Cancellable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* Represents a packet event, which can be cancelled and supports delayed tasks that are executed later.
*/
public class PacketEvent implements Cancellable {
private boolean cancelled;
private List<Runnable> delayedTasks = null;
private final Object packet;
/**
@@ -51,27 +45,6 @@ public class PacketEvent implements Cancellable {
return packet;
}
/**
* Adds a task to be executed later, after the event has been processed.
*
* @param task the task to be added
*/
public void addDelayedTask(Runnable task) {
if (delayedTasks == null) {
delayedTasks = new ArrayList<>();
}
delayedTasks.add(task);
}
/**
* Returns the list of delayed tasks to be executed.
*
* @return a list of tasks, or an empty list if no tasks are added
*/
public List<Runnable> getDelayedTasks() {
return Optional.ofNullable(delayedTasks).orElse(Collections.emptyList());
}
/**
* Checks if the event has been cancelled.
*
@@ -27,15 +27,43 @@ import org.jetbrains.annotations.ApiStatus;
*/
public interface PipelineInjector {
/**
* Sets the user (player) associated with the given Netty channel.
* This is an internal method for managing the mapping between a channel and a player.
*
* @param channel the Netty channel to associate with the player
* @param user the player to associate with the channel
*/
@ApiStatus.Internal
void setUser(Channel channel, CNPlayer user);
/**
* Retrieves the player associated with the given Netty channel.
* This is an internal method for fetching the player mapped to a specific channel.
*
* @param channel the Netty channel for which the player is being retrieved
* @return the player associated with the given channel
*/
@ApiStatus.Internal
CNPlayer getUser(Channel channel);
/**
* Removes the player associated with the specified Netty channel.
* This is an internal method for detaching a player from the given channel.
*
* @param channel the Netty channel from which the player will be removed
* @return the player that was removed, or null if no player was associated
*/
@ApiStatus.Internal
CNPlayer removeUser(Channel channel);
/**
* Retrieves the player associated with the specified object.
* This method is internal and can be used to get a player from various representations.
*
* @param player the object representing the player (could be a reference or other object type)
* @return the player associated with the object
*/
@ApiStatus.Internal
CNPlayer getUser(Object player);
@@ -23,19 +23,21 @@ import net.momirealms.customnameplates.api.CNPlayer;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Represents a tracker for a specific player. This class stores and manages the state of the player
* being tracked, including their crouching status, scale, spectator status, and passengers.
*/
public class Tracker {
private boolean isCrouching;
private double scale;
private boolean isSpectator;
private final CNPlayer tracker;
private final CopyOnWriteArrayList<Integer> passengerIDs = new CopyOnWriteArrayList<>();
/**
* Constructs a new Tracker for the specified player.
* Constructs a new Tracker
*
* @param tracker the player being tracked
* @param tracker the tracker who is tracking the player
*/
public Tracker(CNPlayer tracker) {
this.isCrouching = false;
@@ -43,47 +45,102 @@ public class Tracker {
this.tracker = tracker;
}
/**
* Retrieves the tracker
*
* @return the tracker
*/
public CNPlayer tracker() {
return tracker;
}
/**
* Checks if the tracked player is currently crouching.
*
* @return true if the player is crouching, false otherwise
*/
public boolean isCrouching() {
return isCrouching;
}
/**
* Sets the crouching status for the tracked player.
*
* @param crouching the new crouching status
*/
public void setCrouching(boolean crouching) {
isCrouching = crouching;
}
/**
* Checks if the tracked player is in spectator mode.
*
* @return true if the player is a spectator, false otherwise
*/
public boolean isSpectator() {
return isSpectator;
}
/**
* Sets the spectator status for the tracked player.
*
* @param spectator the new spectator status
*/
public void setSpectator(boolean spectator) {
isSpectator = spectator;
}
/**
* Retrieves the current scale of the tracked player.
*
* @return the scale of the player
*/
public double getScale() {
return scale;
}
/**
* Sets the scale for the tracked player.
*
* @param scale the new scale value
*/
public void setScale(double scale) {
this.scale = scale;
}
/**
* Adds a passenger ID to the list of passengers attached to the tracked player.
*
* @param passengerID the ID of the passenger to add
*/
public void addPassengerID(int passengerID) {
this.passengerIDs.add(passengerID);
}
/**
* Removes a passenger ID from the list of passengers attached to the tracked player.
*
* @param passengerID the ID of the passenger to remove
*/
public void removePassengerID(int passengerID) {
this.passengerIDs.remove((Object) passengerID);
}
/**
* Retrieves the set of passenger IDs attached to the tracked player.
*
* @return a set of passenger IDs
*/
public Set<Integer> getPassengerIDs() {
return new ObjectOpenHashSet<>(passengerIDs);
}
/**
* Checks if the tracked player has no passengers attached.
*
* @return true if the player has no passengers, false otherwise
*/
public boolean isEmpty() {
return passengerIDs.isEmpty();
}
}
}
@@ -23,15 +23,42 @@ import net.momirealms.customnameplates.api.CustomNameplates;
import java.util.Objects;
import java.util.Set;
/**
* An abstract placeholder class
*/
public abstract class AbstractPlaceholder implements Placeholder {
/**
* Placeholder in string format
*/
protected String id;
/**
* The internal id
*/
protected int countId = PlaceholderCounter.getAndIncrease();
/**
* Refresh internal
*/
protected int refreshInterval;
/**
* The PlaceholderManager instance
*/
protected PlaceholderManager manager;
/**
* The nested placeholders
*/
protected Set<Placeholder> children = new ObjectOpenHashSet<>();
/**
* The parent placeholders
*/
protected Set<Placeholder> parents = new ObjectOpenHashSet<>();
/**
* Constructs a new placeholder
*
* @param manager manager
* @param id id
* @param refreshInterval refreshInterval
*/
protected AbstractPlaceholder(PlaceholderManager manager, String id, int refreshInterval) {
if (refreshInterval == 0) {
refreshInterval = -1;
@@ -19,6 +19,9 @@ package net.momirealms.customnameplates.api.placeholder;
import java.util.Set;
/**
* Placeholder
*/
public interface Placeholder {
/**
@@ -17,12 +17,14 @@
package net.momirealms.customnameplates.api.placeholder;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Utility class for managing a global counter for placeholder IDs.
*/
public class PlaceholderCounter {
private static int id = 1;
private static final AtomicInteger ID = new AtomicInteger();
/**
* Returns the current ID and increments the counter by 1.
@@ -30,15 +32,13 @@ public class PlaceholderCounter {
* @return the current ID
*/
public static int getAndIncrease() {
int i = id;
id++;
return i;
return ID.getAndIncrement();
}
/**
* Resets the ID counter back to 1.
*/
public static void reset() {
id = 1;
ID.set(1);
}
}
@@ -27,9 +27,18 @@ import net.momirealms.customnameplates.api.helper.AdventureHelper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* A class that represents an adaptive image combined with dynamic text, allowing
* for the generation of image strings with custom margins, and dynamically rendered text.
* <p>
* This class provides methods to create the full image and text output, including
* any necessary font and shadow adjustments based on specific settings.
* </p>
*
* @param <T> the type of {@link AdaptiveImage} associated with this class
*/
@ApiStatus.Internal
public class AdaptiveImageText<T extends AdaptiveImage> {
private final String id;
private final String text;
private final T t;
@@ -39,6 +48,17 @@ public class AdaptiveImageText<T extends AdaptiveImage> {
private final int leftMargin;
private final int rightMargin;
/**
* Constructs an instance of {@link AdaptiveImageText} with the given parameters.
*
* @param id the unique identifier for this adaptive image text
* @param text the base text to be used in the image
* @param t the {@link AdaptiveImage} object that provides the image
* @param removeShadowOld flag to indicate whether to remove shadow using old method
* @param removeShadowNew flag to indicate whether to remove shadow using new method
* @param leftMargin the left margin for positioning the image
* @param rightMargin the right margin for positioning the image
*/
public AdaptiveImageText(String id, String text, T t, boolean removeShadowOld, boolean removeShadowNew, int rightMargin, int leftMargin) {
this.text = text;
this.id = id;
@@ -50,22 +70,58 @@ public class AdaptiveImageText<T extends AdaptiveImage> {
this.rightMargin = rightMargin;
}
/**
* Creates an instance of {@link AdaptiveImageText} with the specified parameters.
*
* @param id the unique identifier for this adaptive image text
* @param text the base text to be used in the image
* @param t the {@link AdaptiveImage} object that provides the image
* @param removeShadowOld flag to indicate whether to remove shadow using old method
* @param removeShadowNew flag to indicate whether to remove shadow using new method
* @param leftMargin the left margin for positioning the image
* @param rightMargin the right margin for positioning the image
* @param <T> the type of {@link AdaptiveImage} associated with this class
* @return a new instance of {@link AdaptiveImageText}
*/
public static <T extends AdaptiveImage> AdaptiveImageText<T> create(String id, final String text, final T t, final boolean removeShadowOld, final boolean removeShadowNew, int leftMargin, int rightMargin) {
return new AdaptiveImageText<>(id, text, t, removeShadowOld, removeShadowNew, rightMargin, leftMargin);
}
/**
* Gets the pre-parsed dynamic text associated with this adaptive image text.
*
* @return the pre-parsed dynamic text
*/
public PreParsedDynamicText getPreParsedDynamicText() {
return preParsedDynamicText;
}
/**
* Gets the unique identifier for this adaptive image text.
*
* @return the unique identifier
*/
public String getId() {
return id;
}
/**
* Gets the base text associated with this adaptive image text.
*
* @return the base text
*/
public String getText() {
return text;
}
/**
* Generates the full string of text with both the prefix and suffix of the image,
* rendering dynamic content and applying font and shadow adjustments.
*
* @param p1 the first {@link CNPlayer} used for dynamic text rendering
* @param p2 the second {@link CNPlayer} used for dynamic text rendering
* @return the full image and text string
*/
@NotNull
public String getFull(CNPlayer p1, CNPlayer p2) {
String parsed = preParsedDynamicText.fastCreate(p1).render(p2);
@@ -85,6 +141,14 @@ public class AdaptiveImageText<T extends AdaptiveImage> {
return prefixWithFont + parsed + suffixWithFont;
}
/**
* Generates the image string with dynamic content applied, rendering
* the image and applying font and shadow adjustments.
*
* @param p1 the first {@link CNPlayer} used for dynamic text rendering
* @param p2 the second {@link CNPlayer} used for dynamic text rendering
* @return the generated image string
*/
@NotNull
public String getImage(CNPlayer p1, CNPlayer p2) {
String parsed = preParsedDynamicText.fastCreate(p1).render(p2);
@@ -97,11 +161,26 @@ public class AdaptiveImageText<T extends AdaptiveImage> {
return imageWithFont;
}
/**
* Gets the rendered dynamic text for the specified players.
*
* @param p1 the first {@link CNPlayer} used for dynamic text rendering
* @param p2 the second {@link CNPlayer} used for dynamic text rendering
* @return the rendered dynamic text
*/
@NotNull
public String getText(CNPlayer p1, CNPlayer p2) {
return preParsedDynamicText.fastCreate(p1).render(p2);
}
/**
* Generates the text offset characters for the specified players.
* The offsets are calculated based on the rendered text and its advance.
*
* @param p1 the first {@link CNPlayer} used for dynamic text rendering
* @param p2 the second {@link CNPlayer} used for dynamic text rendering
* @return the generated text offset characters
*/
@NotNull
public String getTextOffsetCharacters(CNPlayer p1, CNPlayer p2) {
return OffsetFont.createOffsets(CustomNameplatesAPI.getInstance().getTextAdvance(preParsedDynamicText.fastCreate(p1).render(p2)));
@@ -20,21 +20,48 @@ package net.momirealms.customnameplates.api.placeholder.internal;
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
import org.jetbrains.annotations.ApiStatus;
/**
* Shift Text
*/
@ApiStatus.Internal
public class ShiftText {
/**
* The font associated with the text.
*/
private final String font;
/**
* The pre-parsed dynamic text, allowing for the use of placeholders and dynamic content.
*/
private final PreParsedDynamicText text;
/**
* Constructs a ShiftText instance with the specified font and text.
* The text is parsed dynamically for placeholders and other content.
*
* @param font the font to be associated with the text
* @param text the dynamic text that may contain placeholders to be parsed
*/
public ShiftText(String font, String text) {
this.font = font;
this.text = new PreParsedDynamicText(text);
}
/**
* Retrieves the font associated with this ShiftText.
*
* @return the font as a String
*/
public String getFont() {
return font;
}
/**
* Retrieves the pre-parsed dynamic text associated with this ShiftText.
*
* @return the PreParsedDynamicText instance
*/
public PreParsedDynamicText getText() {
return text;
}
@@ -17,7 +17,20 @@
package net.momirealms.customnameplates.api.placeholder.internal;
/**
* Enum representing the static positions that an element can occupy.
*/
public enum StaticPosition {
LEFT, RIGHT, MIDDLE
}
/**
* Represents the leftmost position.
*/
LEFT,
/**
* Represents the rightmost position.
*/
RIGHT,
/**
* Represents the center position.
*/
MIDDLE
}
@@ -22,43 +22,95 @@ import net.momirealms.customnameplates.api.CustomNameplatesAPI;
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
import org.jetbrains.annotations.ApiStatus;
/**
* Class representing a static text element with customizable width, position, and content.
*/
@ApiStatus.Internal
public class StaticText {
private final int width;
private final StaticPosition position;
private final PreParsedDynamicText text;
/**
* Constructs a new StaticText instance.
*
* @param width the width of the text element (e.g., for layout purposes)
* @param position the static position of the text element (LEFT, RIGHT, MIDDLE)
* @param text the text content to be displayed, which can contain placeholders for dynamic rendering
*/
public StaticText(int width, StaticPosition position, String text) {
this.width = width;
this.position = position;
this.text = new PreParsedDynamicText(text);
}
/**
* Gets the width of the text element.
*
* @return the width of the text element
*/
public int getWidth() {
return width;
}
/**
* Gets the static position of the text element.
*
* @return the position of the text element (LEFT, RIGHT, MIDDLE)
*/
public StaticPosition getPosition() {
return position;
}
/**
* Gets the pre-parsed dynamic text associated with this static text element.
*
* @return the PreParsedDynamicText instance
*/
public PreParsedDynamicText getText() {
return text;
}
/**
* Creates and renders the static text element, using null as the player context.
* <p>
* This method can be useful when rendering static text without needing player-specific dynamic values.
*
* @return the rendered static text as a String
*/
public String create() {
return create(text.fastCreate(null).render(null));
}
/**
* Creates and renders the static text element for a specific player context.
*
* @param player the player whose context will be used for dynamic text rendering
* @return the rendered static text as a String
*/
public String create(CNPlayer player) {
return create(text.fastCreate(player).render(player));
}
/**
* Creates and renders the static text element with two player contexts (for relational rendering).
*
* @param p1 the first player whose context will be used for dynamic text rendering
* @param p2 the second player whose context will be used for relational rendering
* @return the rendered static text as a String
*/
public String create(CNPlayer p1, CNPlayer p2) {
return create(text.fastCreate(p1).render(p2));
}
/**
* A helper method to create and render the static text element with a given plain text.
* <p>
* This method will pass the rendered text, width, and position to the API for final rendering.
*
* @param text the plain text to be rendered
* @return the rendered static text as a String
*/
public String create(String text) {
return CustomNameplatesAPI.getInstance().createStaticText(text, width, position);
}
@@ -25,9 +25,14 @@ import net.momirealms.customnameplates.api.feature.image.Image;
import net.momirealms.customnameplates.api.helper.AdventureHelper;
import org.jetbrains.annotations.ApiStatus;
/**
* Represents a Vanilla HUD (Heads-Up Display) for displaying a dynamic progress bar,
* typically used for showing health, energy, or other stats in a game.
* This class handles the rendering of the HUD, which includes handling the current and maximum values,
* and creating a visual display using a combination of empty, half, and full symbols.
*/
@ApiStatus.Internal
public class VanillaHud {
private final String empty;
private final String half;
private final String full;
@@ -35,6 +40,16 @@ public class VanillaHud {
private final PreParsedDynamicText current;
private final PreParsedDynamicText max;
/**
* Constructs a VanillaHud with the specified parameters.
*
* @param empty The image representing an empty portion of the bar.
* @param half The image representing a half-filled portion of the bar.
* @param full The image representing a fully-filled portion of the bar.
* @param reverse Whether the bar should be reversed (starts from full to empty).
* @param current The current value to be displayed.
* @param max The maximum value to be displayed.
*/
public VanillaHud(Image empty, Image half, Image full, boolean reverse, String current, String max) {
this.empty = String.valueOf(empty.character().character()) + OffsetFont.NEG_2.character();
this.half = String.valueOf(half.character().character()) + OffsetFont.NEG_2.character();
@@ -44,26 +59,61 @@ public class VanillaHud {
this.max = new PreParsedDynamicText(max);
}
/**
* Gets the dynamic text for the current value.
*
* @return The dynamic text for the current value.
*/
public PreParsedDynamicText getCurrent() {
return current;
}
/**
* Gets the dynamic text for the maximum value.
*
* @return The dynamic text for the maximum value.
*/
public PreParsedDynamicText getMax() {
return max;
}
/**
* Creates and renders the HUD for a general case (with no player context).
*
* @return The rendered HUD as a string.
*/
public String create() {
return create(current.fastCreate(null).render(null), max.fastCreate(null).render(null));
}
/**
* Creates and renders the HUD for a specific player.
*
* @param player The player whose current and max values will be rendered.
* @return The rendered HUD as a string.
*/
public String create(CNPlayer player) {
return create(current.fastCreate(player).render(player), max.fastCreate(player).render(player));
}
/**
* Creates and renders the HUD for two players, using their respective values.
*
* @param p1 The first player.
* @param p2 The second player.
* @return The rendered HUD as a string.
*/
public String create(CNPlayer p1, CNPlayer p2) {
return create(current.fastCreate(p1).render(p2), max.fastCreate(p1).render(p2));
}
/**
* Creates the actual HUD string representation, based on current and max values.
*
* @param current The current value as a string.
* @param max The maximum value as a string.
* @return The constructed and rendered HUD as a string.
*/
private String create(String current, String max) {
double currentDouble;
double maxDouble;
@@ -24,7 +24,9 @@ import net.momirealms.customnameplates.api.CustomNameplates;
* A requirement that is always satisfied, representing an "empty" or default requirement.
*/
public class EmptyRequirement implements Requirement {
/**
* A requirement that is always satisfied, representing an "empty" or default requirement.
*/
public static final EmptyRequirement INSTANCE = new EmptyRequirement();
/**
@@ -23,6 +23,9 @@ import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Interface to manage data storage
*/
public interface StorageManager extends Reloadable {
/**
@@ -17,14 +17,67 @@
package net.momirealms.customnameplates.api.storage;
/**
* Enum representing the various types of storage systems supported for data persistence.
* <p>
* Each enum constant corresponds to a different type of storage backend that can be used
* for saving and retrieving data. This includes file-based storage (JSON, YAML), relational
* databases (H2, SQLite, MySQL, MariaDB), NoSQL databases (MongoDB), and caching systems (Redis).
* </p>
*/
public enum StorageType {
/**
* Represents storage in JSON format.
* This format is typically used for lightweight data storage and easy serialization.
*/
JSON,
/**
* Represents storage in YAML format.
* YAML is often used for configuration files and is human-readable.
*/
YAML,
/**
* Represents storage in an H2 database.
* H2 is an in-memory SQL database that can also be used in file-based mode.
*/
H2,
/**
* Represents storage in an SQLite database.
* SQLite is a serverless, self-contained SQL database engine.
*/
SQLITE,
/**
* Represents storage in a MySQL database.
* MySQL is a widely used relational database management system (RDBMS).
*/
MYSQL,
/**
* Represents storage in a MariaDB database.
* MariaDB is a community-developed, open-source RDBMS that is a fork of MySQL.
*/
MARIADB,
MONGODB,
/**
* Represents storage in a MongoDB database.
* MongoDB is a NoSQL database that stores data in flexible, JSON-like documents.
*/
MONGODB,
/**
* Represents storage in Redis.
* Redis is an in-memory data structure store, used as a database, cache, and message broker.
*/
Redis,
/**
* Represents the absence of a storage type.
* This is used when no storage system is configured or required.
*/
NONE
}
@@ -36,33 +36,57 @@ public class JsonData {
private int flags;
/**
* Constructs a new {@link JsonData} instance.
* Constructs a new {@link JsonData} instance with the specified nameplate and bubble, setting flags to 0.
*
* @param nameplate the nameplate value
* @param bubble the bubble value
*/
public JsonData(String nameplate, String bubble) {
this.nameplate = nameplate;
this.bubble = bubble;
this.flags = 0;
this(nameplate, bubble, 0);
}
/**
* Constructs a new {@link JsonData} instance with the specified nameplate, bubble, and flags.
*
* @param nameplate the nameplate value
* @param bubble the bubble value
* @param flags the flags value
*/
public JsonData(String nameplate, String bubble, int flags) {
this.nameplate = nameplate;
this.bubble = bubble;
this.flags = flags;
}
/**
* Constructs a new {@link JsonData} instance with the specified nameplate, bubble, and a preview state flag.
*
* @param nameplate the nameplate value
* @param bubble the bubble value
* @param previewState the preview state
*/
public JsonData(String nameplate, String bubble, boolean previewState) {
this.nameplate = nameplate;
this.bubble = bubble;
this.flags = encodeFlags(previewState);
}
/**
* Encodes the preview state as a flag (0 or 1).
*
* @param previewState the preview state
* @return 1 if preview state is true, otherwise 0
*/
public static int encodeFlags(boolean previewState) {
return previewState ? 1 : 0;
}
/**
* Decodes the preview state from the flags.
*
* @param flags the flags value
* @return true if the preview state flag is set, otherwise false
*/
public static boolean decodePreviewState(int flags) {
return (flags & 1) == 1;
}
@@ -23,8 +23,13 @@ import java.util.UUID;
* Represents player-specific data, including the player's nameplate, bubble, and UUID.
*/
public interface PlayerData {
/**
* Default nameplate
*/
String DEFAULT_NAMEPLATE = "none";
/**
* Default bubble
*/
String DEFAULT_BUBBLE = "none";
/**
@@ -24,13 +24,27 @@ import java.util.UUID;
* It includes the player's name, their nameplate and bubble data.
*/
public class PlayerDataImpl implements PlayerData {
/**
* The UUID of the player
*/
protected UUID uuid;
/**
* The nameplate identifier for the player
*/
protected String nameplate;
/**
* The bubble identifier for the player
*/
protected String bubble;
/**
* Flag indicating whether preview tags are enabled
*/
protected boolean previewTags;
public PlayerDataImpl(UUID uuid, String nameplate, String bubble, boolean previewTags) {
private PlayerDataImpl(UUID uuid, String nameplate, String bubble, boolean previewTags) {
this.uuid = uuid;
this.nameplate = nameplate;
this.bubble = bubble;
@@ -17,18 +17,44 @@
package net.momirealms.customnameplates.api.util;
/**
* Enum representing text alignment options.
* <p>
* This enum provides three types of text alignment: CENTER, LEFT, and RIGHT, each associated
* with a unique ID for easy identification. These values are typically used to define the
* positioning of text in layouts or UI components.
* </p>
*/
public enum Alignment {
/**
* Represents center-aligned text.
*/
CENTER(0),
/**
* Represents left-aligned text.
*/
LEFT(1),
/**
* Represents right-aligned text.
*/
RIGHT(2);
final int id;
/**
* Constructs an {@code Alignment} instance with the specified ID.
*
* @param id the unique ID representing this alignment type
*/
Alignment(int id) {
this.id = id;
}
/**
* Retrieves the ID associated with this alignment.
*
* @return the unique ID of this alignment
*/
public int getId() {
return id;
}
@@ -0,0 +1,18 @@
package net.momirealms.customnameplates.api.util;
public enum Billboard {
FIXED(0),
VERTICAL(1),
HORIZONTAL(2),
CENTER(3);
private final byte id;
Billboard(int index) {
this.id = (byte) index;
}
public byte id() {
return id;
}
}
@@ -19,8 +19,21 @@ package net.momirealms.customnameplates.api.util;
import java.util.ArrayList;
/**
* Utility class for handling character and Unicode conversions.
* This class provides methods to convert between Unicode escape sequences, character arrays,
* and code points, as well as converting characters to their Unicode representations.
*/
public class CharacterUtils {
private CharacterUtils() {}
/**
* Converts a Unicode string (e.g., "\\u0041\\u0042") into an array of characters.
*
* @param unicodeString a string containing Unicode escape sequences (e.g., "\\u0041\\u0042")
* @return a character array corresponding to the Unicode string
*/
public static char[] unicodeToChars(String unicodeString) {
String processedString = unicodeString.replace("\\u", "");
int length = processedString.length() / 4;
@@ -37,6 +50,14 @@ public class CharacterUtils {
return chars;
}
/**
* Converts a character array to a single Unicode code point. If the array contains two characters
* (a high surrogate and a low surrogate), it is combined into a single supplementary code point.
*
* @param chars the character array to convert
* @return the Unicode code point corresponding to the character(s)
* @throws IllegalArgumentException if the character array contains more than 2 characters
*/
public static int toCodePoint(char[] chars) {
if (chars.length == 1) {
return chars[0];
@@ -47,6 +68,14 @@ public class CharacterUtils {
}
}
/**
* Converts a character array to an array of Unicode code points. If the array contains surrogate pairs,
* they are combined into a single supplementary code point.
*
* @param chars the character array to convert
* @return an array of Unicode code points corresponding to the characters
* @throws IllegalArgumentException if there is an illegal surrogate pair
*/
public static int[] toCodePoints(char[] chars) {
ArrayList<Integer> codePoints = new ArrayList<>();
for (int i = 0; i < chars.length; i++) {
@@ -67,6 +96,12 @@ public class CharacterUtils {
return codePoints.stream().mapToInt(i -> i).toArray();
}
/**
* Converts a single character to its Unicode escape sequence (e.g., '\\u0041' for 'A').
*
* @param c the character to convert
* @return a string representing the Unicode escape sequence for the character
*/
public static String char2Unicode(char c) {
StringBuilder stringBuilder_1 = new StringBuilder("\\u");
StringBuilder stringBuilder_2 = new StringBuilder(Integer.toHexString(c));
@@ -76,6 +111,12 @@ public class CharacterUtils {
return stringBuilder_1.toString();
}
/**
* Converts an array of characters to their Unicode escape sequences.
*
* @param c the character array to convert
* @return a string representing the Unicode escape sequences for all characters in the array
*/
public static String char2Unicode(char[] c) {
StringBuilder builder = new StringBuilder();
for (char value : c) {
@@ -25,8 +25,19 @@ import net.momirealms.customnameplates.api.requirement.Requirement;
import java.io.File;
import java.util.*;
/**
* Utility class providing various helper methods for handling configuration data
*/
public class ConfigUtils {
private ConfigUtils() {}
/**
* Creates a {@link CarouselText} object from the provided configuration section.
*
* @param section the configuration section containing properties for the CarouselText.
* @return a {@link CarouselText} instance created from the section data.
*/
public static CarouselText carouselText(Section section) {
return new CarouselText(
section.getInt("duration", 200),
@@ -36,6 +47,12 @@ public class ConfigUtils {
);
}
/**
* Creates an array of {@link CarouselText} objects, sorted by their order from the given configuration section.
*
* @param section the configuration section containing multiple CarouselText entries.
* @return an array of {@link CarouselText} instances, sorted by order.
*/
public static CarouselText[] carouselTexts(Section section) {
TreeMap<Integer, CarouselText> map = new TreeMap<>();
if (section == null) {
@@ -58,10 +75,22 @@ public class ConfigUtils {
return map.values().toArray(new CarouselText[0]);
}
/**
* Converts a comma-separated string to an ARGB color value.
*
* @param arg the comma-separated string representing the ARGB color.
* @return the corresponding ARGB color integer value.
*/
public static int argb(String arg) {
return argb(arg.split(","));
}
/**
* Converts an array of strings to an ARGB color value.
*
* @param args an array of strings representing ARGB components (alpha, red, green, blue).
* @return the corresponding ARGB color integer value.
*/
public static int argb(String[] args) {
int alpha = args.length >= 1 ? Integer.parseInt(args[0]) : 64;
int red = args.length >= 2 ? Integer.parseInt(args[1]) : 0;
@@ -70,14 +99,35 @@ public class ConfigUtils {
return argb(alpha, red, green, blue);
}
/**
* Converts the given ARGB components to a single ARGB integer value.
*
* @param alpha the alpha component of the color.
* @param red the red component of the color.
* @param green the green component of the color.
* @param blue the blue component of the color.
* @return the corresponding ARGB color integer value.
*/
public static int argb(int alpha, int red, int green, int blue) {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
/**
* Converts a comma-separated string to a {@link Vector3} object.
*
* @param arg the comma-separated string representing the vector (x, y, z).
* @return the corresponding {@link Vector3} object.
*/
public static Vector3 vector3(String arg) {
return vector3(arg.split(","));
}
/**
* Converts an array of strings to a {@link Vector3} object.
*
* @param args an array of strings representing the x, y, and z components of the vector.
* @return the corresponding {@link Vector3} object.
*/
public static Vector3 vector3(String[] args) {
float x = args.length >= 1 ? Float.parseFloat(args[0]) : 0f;
float y = args.length >= 2 ? Float.parseFloat(args[1]) : 0f;
@@ -85,10 +135,24 @@ public class ConfigUtils {
return vector3(x, y, z);
}
/**
* Creates a {@link Vector3} object from the provided float components.
*
* @param x the x component of the vector.
* @param y the y component of the vector.
* @param z the z component of the vector.
* @return the corresponding {@link Vector3} object.
*/
public static Vector3 vector3(float x, float y, float z) {
return new Vector3(x, y, z);
}
/**
* Recursively retrieves all configuration files with a ".yml" extension from the given folder and its subfolders.
*
* @param configFolder the root folder to start searching for YAML files.
* @return a list of valid configuration files sorted by name.
*/
public static List<File> getConfigsDeeply(File configFolder) {
ArrayList<File> validConfigs = new ArrayList<>();
Deque<File> fileDeque = new ArrayDeque<>();
@@ -109,11 +173,26 @@ public class ConfigUtils {
return validConfigs;
}
/**
* Retrieves a file located in the same folder as the provided file, with a new name.
*
* @param file the base file.
* @param fileName the name of the file to retrieve.
* @return the file located in the same folder with the specified name.
*/
public static File getFileInTheSameFolder(File file, String fileName) {
File folder = file.getParentFile();
return new File(folder, fileName);
}
/**
* Safely casts an object to the specified type, logging an error if the cast fails.
*
* @param object the object to cast.
* @param clazz the class type to cast to.
* @param <T> the type to cast to.
* @return the cast object if successful, or null if the cast fails.
*/
public static <T> T safeCast(Object object, Class<T> clazz) {
try {
return clazz.cast(object);
@@ -123,3 +202,4 @@ public class ConfigUtils {
}
}
}
@@ -19,13 +19,33 @@ package net.momirealms.customnameplates.api.util;
import java.util.concurrent.ThreadLocalRandom;
/**
* A utility class for generating self-incrementing entity IDs.
* The class provides a thread-safe method for generating unique IDs that increase with each call.
* The IDs are randomly initialized within a specific range to ensure non-repetition across instances.
*/
public class SelfIncreaseEntityID {
/**
* Private constructor to prevent instantiation of this utility class.
*/
private SelfIncreaseEntityID() {}
/**
* The current entity ID, initialized with a random value in a specific range.
* The value is incremented each time {@link #getAndIncrease()} is called.
*/
private static int id = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE / 4, Integer.MAX_VALUE / 3);
/**
* Retrieves the current entity ID and increments it for the next call.
* This method ensures that each ID is unique and increases incrementally.
*
* @return the current entity ID before it is incremented
*/
public static int getAndIncrease() {
int i = id;
id++;
return i;
}
}
}
@@ -19,22 +19,55 @@ package net.momirealms.customnameplates.api.util;
import net.momirealms.customnameplates.api.CustomNameplates;
/**
* A simple record representing a 3D vector with `x`, `y`, and `z` coordinates.
* Provides utility methods for vector arithmetic such as addition and scaling.
*/
public record Vector3(double x, double y, double z) {
/**
* A constant representing a zero vector (0, 0, 0).
*/
public static final Vector3 ZERO = new Vector3(0, 0, 0);
/**
* Converts the vector into a platform-specific 3D vector representation.
*
* @return A platform-specific 3D vector object.
*/
public Object toVec3() {
return CustomNameplates.getInstance().getPlatform().vec3(x, y, z);
}
/**
* Adds another vector to this vector and returns a new resulting vector.
*
* @param another The vector to be added to this vector.
* @return A new `Vector3` representing the sum of this vector and the given vector.
*/
public Vector3 add(Vector3 another) {
return new Vector3(this.x + another.x, this.y + another.y, this.z + another.z);
}
/**
* Adds the given `x`, `y`, and `z` values to the respective components of this vector
* and returns a new resulting vector.
*
* @param x The value to add to the `x` component.
* @param y The value to add to the `y` component.
* @param z The value to add to the `z` component.
* @return A new `Vector3` representing the sum of this vector and the given values.
*/
public Vector3 add(double x, double y, double z) {
return new Vector3(this.x + x, this.y + y, this.z + z);
}
/**
* Scales this vector by a given factor and returns a new resulting vector.
*
* @param value The factor to multiply each component of the vector by.
* @return A new `Vector3` representing the scaled vector.
*/
public Vector3 multiply(double value) {
return new Vector3(this.x * value, this.y * value, this.z * value);
}
@@ -26,8 +26,25 @@ import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Utility class for zipping files and directories.
* Provides methods for zipping entire directories and adding individual files to a zip archive.
*/
public class ZipUtils {
/**
* Private constructor to prevent instantiation of utility class.
*/
private ZipUtils() {}
/**
* Zips the contents of a directory into a zip file.
* This method recursively walks through the directory and adds each file to the zip archive.
*
* @param folderPath The path to the folder to be zipped.
* @param zipFilePath The path to the output zip file.
* @throws IOException If an I/O error occurs while reading the directory or writing the zip file.
*/
public static void zipDirectory(Path folderPath, Path zipFilePath) throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath.toFile()))) {
try (Stream<Path> paths = Files.walk(folderPath)) {
@@ -45,6 +62,14 @@ public class ZipUtils {
}
}
/**
* Adds a file's contents to the zip archive.
*
* @param zipEntry The zip entry (file) to be added to the zip archive.
* @param is The input stream from which the file contents are read.
* @param zos The zip output stream where the file will be written.
* @throws IOException If an I/O error occurs while writing the file to the zip archive.
*/
public static void addToZip(ZipEntry zipEntry, InputStream is, ZipOutputStream zos) throws IOException {
zos.putNextEntry(zipEntry);
byte[] buffer = new byte[4096];
@@ -0,0 +1,161 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.command;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import net.momirealms.customnameplates.common.sender.SenderFactory;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.context.CommandContext;
/**
* Abstract base class for command feature implementations within the Custom Nameplates command system.
* This class provides utility methods for command registration, feedback handling, and configuration.
*
* @param <C> The type of the sender (e.g., a player or console sender) for the command.
*/
public abstract class AbstractCommandFeature<C> implements CommandFeature<C> {
/**
* The command manager
*/
protected final CustomNameplatesCommandManager<C> commandManager;
/**
* The command config
*/
protected CommandConfig commandConfig;
/**
* Constructs an AbstractCommandFeature instance with the given command manager.
*
* @param commandManager The command manager to manage the commands associated with this feature.
*/
public AbstractCommandFeature(CustomNameplatesCommandManager<C> commandManager) {
this.commandManager = commandManager;
}
/**
* Abstract method to retrieve the sender factory for the command.
* Implementations must provide the logic for creating senders of type C.
*
* @return The sender factory for the command.
*/
protected abstract SenderFactory<?, C> getSenderFactory();
/**
* Abstract method to assemble the command builder with the given manager.
* Implementations must define how to build the command.
*
* @param manager The command manager responsible for managing the command.
* @param builder The builder used to construct the command.
* @return A command builder ready to be built.
*/
public abstract Command.Builder<? extends C> assembleCommand(CommandManager<C> manager, Command.Builder<C> builder);
/**
* Registers the command with the provided command manager.
* This method builds the command and registers it with the command manager.
*
* @param manager The command manager to register the command with.
* @param builder The builder used to create the command.
* @return The registered command.
*/
@Override
@SuppressWarnings("unchecked")
public Command<C> registerCommand(CommandManager<C> manager, Command.Builder<C> builder) {
Command<C> command = (Command<C>) assembleCommand(manager, builder).build();
manager.command(command);
return command;
}
/**
* Registers any related functions or hooks. This method is a no-op by default
* and can be overridden in subclasses to register additional functionality.
*/
@Override
public void registerRelatedFunctions() {
// empty
}
/**
* Unregisters any related functions or hooks. This method is a no-op by default
* and can be overridden in subclasses to unregister additional functionality.
*/
@Override
public void unregisterRelatedFunctions() {
// empty
}
/**
* Handles feedback for the command execution, sending a translation message to the sender.
* The feedback is suppressed if the "silent" flag is present in the command context.
*
* @param context The command context containing information about the sender and flags.
* @param key The key for the translation component to be used as feedback.
* @param args The arguments to be passed to the translation.
*/
@Override
@SuppressWarnings("unchecked")
public void handleFeedback(CommandContext<?> context, TranslatableComponent.Builder key, Component... args) {
if (context.flags().hasFlag("silent")) {
return;
}
commandManager.handleCommandFeedback((C) context.sender(), key, args);
}
/**
* Handles feedback for the command execution, sending a translation message to the sender.
*
* @param sender The sender to receive the feedback.
* @param key The key for the translation component to be used as feedback.
* @param args The arguments to be passed to the translation.
*/
@Override
public void handleFeedback(C sender, TranslatableComponent.Builder key, Component... args) {
commandManager.handleCommandFeedback(sender, key, args);
}
/**
* Retrieves the command manager associated with this feature.
*
* @return The command manager.
*/
@Override
public CustomNameplatesCommandManager<C> getCustomNameplatesCommandManager() {
return commandManager;
}
/**
* Retrieves the configuration associated with the command.
*
* @return The command configuration.
*/
@Override
public CommandConfig getCommandConfig() {
return commandConfig;
}
/**
* Sets the configuration for the command.
*
* @param commandConfig The configuration to set for the command.
*/
public void setCommandConfig(CommandConfig commandConfig) {
this.commandConfig = commandConfig;
}
}
@@ -49,17 +49,39 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
* An abstract implementation of the {@link CustomNameplatesCommandManager} that handles the management and registration of command features,
* exception handling, and feedback handling within the Custom Nameplates plugin.
*
* @param <C> The type of the sender (e.g., player, console) for the commands.
*/
public abstract class AbstractCommandManager<C> implements CustomNameplatesCommandManager<C> {
/**
* Registered commands
*/
protected final HashSet<CommandComponent<C>> registeredRootCommandComponents = new HashSet<>();
/**
* Registered features
*/
protected final HashSet<CommandFeature<C>> registeredFeatures = new HashSet<>();
/**
* The command manager
*/
protected final CommandManager<C> commandManager;
/**
* The NameplatesPlugin
*/
protected final NameplatesPlugin plugin;
private final CustomNameplatesCaptionFormatter<C> captionFormatter = new CustomNameplatesCaptionFormatter<C>();
private final MinecraftExceptionHandler.Decorator<C> decorator = (formatter, ctx, msg) -> msg;
private TriConsumer<C, String, Component> feedbackConsumer;
/**
* Constructs an AbstractCommandManager instance with the provided plugin and command manager.
*
* @param plugin The plugin instance managing this command manager.
* @param commandManager The command manager instance that handles the command registration.
*/
public AbstractCommandManager(NameplatesPlugin plugin, CommandManager<C> commandManager) {
this.commandManager = commandManager;
this.plugin = plugin;
@@ -86,6 +108,12 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
});
}
/**
* Wraps a sender base on platform
*
* @param c sender
* @return the wrapped sender
*/
protected abstract Sender wrapSender(C c);
private void inject() {
@@ -108,7 +136,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
}
@Override
public CommandConfig<C> getCommandConfig(YamlDocument document, String featureID) {
public CommandConfig getCommandConfig(YamlDocument document, String featureID) {
Section section = document.getSection(featureID);
if (section == null) return null;
return new CommandConfig.Builder<C>()
@@ -119,7 +147,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
}
@Override
public Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig<C> config) {
public Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig config) {
ArrayList<Command.Builder<C>> list = new ArrayList<>();
for (String usage : config.getUsages()) {
if (!usage.startsWith("/")) continue;
@@ -135,7 +163,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
}
@Override
public void registerFeature(CommandFeature<C> feature, CommandConfig<C> config) {
public void registerFeature(CommandFeature<C> feature, CommandConfig config) {
if (!config.isEnable()) throw new RuntimeException("Registering a disabled command feature is not allowed");
for (Command.Builder<C> builder : buildCommandBuilders(config)) {
Command<C> command = feature.registerCommand(commandManager, builder);
@@ -155,7 +183,7 @@ public abstract class AbstractCommandManager<C> implements CustomNameplatesComma
throw new RuntimeException(e);
}
this.getFeatures().values().forEach(feature -> {
CommandConfig<C> config = getCommandConfig(document, feature.getFeatureID());
CommandConfig config = getCommandConfig(document, feature.getFeatureID());
if (config.isEnable()) {
registerFeature(feature, config);
}
@@ -0,0 +1,116 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.command;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
/**
* A builder interface for constructing commands with configurable parameters.
* This interface allows setting permissions, command nodes (subcommands), and
* building the final {@link Command.Builder} object.
*/
public interface CommandBuilder<C> {
/**
* Sets the permission required to execute the command.
*
* @param permission the permission string required for executing the command.
* @return the current {@link CommandBuilder} instance for method chaining.
*/
CommandBuilder<C> setPermission(String permission);
/**
* Sets the subcommands (nodes) for the command.
* This allows defining a hierarchy of commands.
*
* @param subNodes the subcommands or nodes to add to the command.
* @return the current {@link CommandBuilder} instance for method chaining.
*/
CommandBuilder<C> setCommandNode(String... subNodes);
/**
* Retrieves the fully constructed {@link Command.Builder} instance.
* This method returns the builder object that can be used to further configure
* and register the command.
*
* @return the built {@link Command.Builder} instance.
*/
Command.Builder<C> getBuiltCommandBuilder();
/**
* Basic implementation of the {@link CommandBuilder} interface.
* This class provides a default implementation for constructing a command
* with the given root node, permission, and subcommand nodes.
*
* @param <C> The type of context or object associated with the command.
*/
class BasicCommandBuilder<C> implements CommandBuilder<C> {
/**
* The actual command builder used to construct the command.
*/
private Command.Builder<C> commandBuilder;
/**
* Constructs a new {@link BasicCommandBuilder} for building a command.
*
* @param commandManager the {@link CommandManager} instance used for creating the command builder.
* @param rootNode the root node for the command.
*/
public BasicCommandBuilder(CommandManager<C> commandManager, String rootNode) {
this.commandBuilder = commandManager.commandBuilder(rootNode);
}
/**
* Sets the permission for the command.
*
* @param permission the permission required for executing the command.
* @return the current {@link CommandBuilder} instance for method chaining.
*/
@Override
public CommandBuilder<C> setPermission(String permission) {
this.commandBuilder = this.commandBuilder.permission(permission);
return this;
}
/**
* Sets the subcommands (nodes) for the command.
*
* @param subNodes the subcommands to add to the command.
* @return the current {@link CommandBuilder} instance for method chaining.
*/
@Override
public CommandBuilder<C> setCommandNode(String... subNodes) {
for (String sub : subNodes) {
this.commandBuilder = this.commandBuilder.literal(sub);
}
return this;
}
/**
* Retrieves the built {@link Command.Builder} instance.
*
* @return the built {@link Command.Builder} instance.
*/
@Override
public Command.Builder<C> getBuiltCommandBuilder() {
return commandBuilder;
}
}
}
@@ -0,0 +1,157 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.command;
import java.util.ArrayList;
import java.util.List;
/**
* A configuration class for setting up command-related options such as enabling/disabling,
* command usages, and required permissions.
* <p>
* This class provides a builder pattern implementation to easily create and configure
* a {@link CommandConfig} object with a fluent API.
*/
public class CommandConfig {
/**
* Flag indicating whether the command is enabled.
*/
private boolean enable = false;
/**
* List of command usage examples or syntax hints.
*/
private List<String> usages = new ArrayList<>();
/**
* Permission required to execute the command.
*/
private String permission = null;
/**
* Private constructor to prevent direct instantiation.
* Use the {@link Builder} class to construct an instance.
*/
private CommandConfig() {
}
/**
* Constructs a new {@link CommandConfig} with the specified values.
*
* @param enable whether the command is enabled.
* @param usages the list of command usages.
* @param permission the permission required to execute the command.
*/
public CommandConfig(boolean enable, List<String> usages, String permission) {
this.enable = enable;
this.usages = usages;
this.permission = permission;
}
/**
* Gets whether the command is enabled.
*
* @return true if the command is enabled, false otherwise.
*/
public boolean isEnable() {
return enable;
}
/**
* Gets the list of command usages or syntax examples.
*
* @return the list of command usages.
*/
public List<String> getUsages() {
return usages;
}
/**
* Gets the permission required to execute the command.
*
* @return the permission string.
*/
public String getPermission() {
return permission;
}
/**
* Builder class for constructing a {@link CommandConfig} object with customizable options.
* This allows setting values for enabling the command, defining usages, and setting permissions.
*
* @param <C> the context type associated with the command.
*/
public static class Builder<C> {
/**
* The {@link CommandConfig} object being built.
*/
private final CommandConfig config;
/**
* Constructs a new {@link Builder} for {@link CommandConfig}.
* Initializes the config object to default values.
*/
public Builder() {
this.config = new CommandConfig();
}
/**
* Sets the list of command usages (examples or syntax hints).
*
* @param usages the list of command usages.
* @return the current {@link Builder} instance for method chaining.
*/
public Builder<C> usages(List<String> usages) {
config.usages = usages;
return this;
}
/**
* Sets the permission required to execute the command.
*
* @param permission the permission string.
* @return the current {@link Builder} instance for method chaining.
*/
public Builder<C> permission(String permission) {
config.permission = permission;
return this;
}
/**
* Sets whether the command is enabled.
*
* @param enable true to enable the command, false to disable it.
* @return the current {@link Builder} instance for method chaining.
*/
public Builder<C> enable(boolean enable) {
config.enable = enable;
return this;
}
/**
* Builds and returns the constructed {@link CommandConfig} object.
*
* @return the {@link CommandConfig} object.
*/
public CommandConfig build() {
return config;
}
}
}
@@ -0,0 +1,95 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.command;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.context.CommandContext;
/**
* Represents the contract for a feature that provides a command in the Custom Nameplates system.
* This interface defines methods for registering commands, handling feedback, and managing related functionality.
*
* @param <C> The type of the sender (e.g., player, console) for the command.
*/
public interface CommandFeature<C> {
/**
* Registers the command with the provided command manager and builder.
*
* @param cloudCommandManager The command manager responsible for managing commands.
* @param builder The command builder used to create the command.
* @return The registered command.
*/
Command<C> registerCommand(CommandManager<C> cloudCommandManager, Command.Builder<C> builder);
/**
* Retrieves a unique identifier for this feature.
* The feature ID is used to identify the feature within the system.
*
* @return A unique identifier for this command feature.
*/
String getFeatureID();
/**
* Registers any related functions or hooks that this feature may require.
* This method may be used to register additional functionality necessary for the feature.
*/
void registerRelatedFunctions();
/**
* Unregisters any related functions or hooks that were previously registered.
* This method is used for cleaning up after the feature when it's no longer needed.
*/
void unregisterRelatedFunctions();
/**
* Handles feedback for the command execution, sending a translation message to the sender.
* The feedback may be affected by the flags in the command context (e.g., silent mode).
*
* @param context The command context containing information about the sender and flags.
* @param key The key for the translation component to be used as feedback.
* @param args The arguments to be passed to the translation.
*/
void handleFeedback(CommandContext<?> context, TranslatableComponent.Builder key, Component... args);
/**
* Handles feedback for the command execution, sending a translation message to the sender.
*
* @param sender The sender to receive the feedback.
* @param key The key for the translation component to be used as feedback.
* @param args The arguments to be passed to the translation.
*/
void handleFeedback(C sender, TranslatableComponent.Builder key, Component... args);
/**
* Retrieves the command manager associated with this feature.
*
* @return The command manager.
*/
CustomNameplatesCommandManager<C> getCustomNameplatesCommandManager();
/**
* Retrieves the configuration associated with the command.
*
* @return The command configuration.
*/
CommandConfig getCommandConfig();
}
@@ -0,0 +1,124 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.command;
import dev.dejvokep.boostedyaml.YamlDocument;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.util.Index;
import net.momirealms.customnameplates.common.util.TriConsumer;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Interface for managing commands within the Custom Nameplates plugin. This interface defines methods for
* registering features, handling feedback, and interacting with the command manager and configurations.
*
* @param <C> The type of the sender (e.g., player, console) for the commands.
*/
public interface CustomNameplatesCommandManager<C> {
/**
* The default configuration file name for commands
*/
String commandsFile = "commands.yml";
/**
* Unregisters all previously registered command features.
*/
void unregisterFeatures();
/**
* Registers a command feature with the provided configuration.
*
* @param feature The command feature to register.
* @param config The configuration for the feature.
*/
void registerFeature(CommandFeature<C> feature, CommandConfig config);
/**
* Registers all default features based on the plugin configuration.
*/
void registerDefaultFeatures();
/**
* Retrieves all registered command features in the form of an index.
*
* @return The index of registered command features.
*/
Index<String, CommandFeature<C>> getFeatures();
/**
* Sets a custom feedback consumer that handles the feedback sent to the command sender.
*
* @param feedbackConsumer The custom feedback consumer.
*/
void setFeedbackConsumer(@NotNull TriConsumer<C, String, Component> feedbackConsumer);
/**
* Provides the default feedback consumer for sending feedback messages.
*
* @return The default feedback consumer.
*/
TriConsumer<C, String, Component> defaultFeedbackConsumer();
/**
* Retrieves the command configuration from a YAML document and a given feature ID.
*
* @param document The YAML document containing the configuration.
* @param featureID The ID of the feature to retrieve configuration for.
* @return The command configuration for the specified feature, or null if not found.
*/
CommandConfig getCommandConfig(YamlDocument document, String featureID);
/**
* Builds a collection of command builders based on the given configuration.
*
* @param config The command configuration.
* @return A collection of command builders.
*/
Collection<Command.Builder<C>> buildCommandBuilders(CommandConfig config);
/**
* Retrieves the command manager associated with this command manager.
*
* @return The command manager.
*/
CommandManager<C> getCommandManager();
/**
* Sends feedback to the sender based on the provided key and arguments.
*
* @param sender The sender of the command.
* @param key The key used to retrieve the feedback message.
* @param args The arguments to be included in the feedback message.
*/
void handleCommandFeedback(C sender, TranslatableComponent.Builder key, Component... args);
/**
* Sends feedback to the sender based on the provided node and component.
*
* @param sender The sender of the command.
* @param node The feedback node.
* @param component The component containing the feedback message.
*/
void handleCommandFeedback(C sender, String node, Component component);
}
@@ -1,26 +1,18 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
* Copyright (C) <2024> <XiaoMoMi>
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.dependency;
@@ -356,10 +348,27 @@ public enum Dependency {
private static final String MAVEN_FORMAT = "%s/%s/%s/%s-%s.jar";
/**
* Constructs a Dependency with the given group ID, artifact ID, repository, and custom artifact ID.
*
* @param groupId the group ID of the dependency
* @param artifactId the artifact ID of the dependency
* @param repo the repository for the dependency
* @param customArtifactID the custom artifact ID for the dependency
*/
Dependency(String groupId, String artifactId, String repo, String customArtifactID) {
this(groupId, artifactId, repo, customArtifactID, new Relocation[0]);
}
/**
* Constructs a Dependency with the given group ID, artifact ID, repository, custom artifact ID, and relocations.
*
* @param groupId the group ID of the dependency
* @param artifactId the artifact ID of the dependency
* @param repo the repository for the dependency
* @param customArtifactID the custom artifact ID for the dependency
* @param relocations any relocations associated with the dependency
*/
Dependency(String groupId, String artifactId, String repo, String customArtifactID, Relocation... relocations) {
this.artifactId = artifactId;
this.artifactIdSuffix = "";
@@ -369,6 +378,16 @@ public enum Dependency {
this.customArtifactID = customArtifactID;
}
/**
* Constructs a Dependency with the given group ID, artifact ID, repository, custom artifact ID, and relocations.
*
* @param groupId the group ID of the dependency
* @param artifactId the artifact ID of the dependency
* @param repo the repository for the dependency
* @param customArtifactID the custom artifact ID for the dependency
* @param artifactIdSuffix the custom artifact suffix
* @param relocations any relocations associated with the dependency
*/
Dependency(String groupId, String artifactId, String repo, String customArtifactID, String artifactIdSuffix, Relocation... relocations) {
this.artifactId = artifactId;
this.artifactIdSuffix = artifactIdSuffix;
@@ -378,10 +397,20 @@ public enum Dependency {
this.customArtifactID = customArtifactID;
}
/**
* Sets the artifact suffix
*
* @param artifactIdSuffix the artifact suffix
*/
public void setArtifactIdSuffix(String artifactIdSuffix) {
this.artifactIdSuffix = artifactIdSuffix;
}
/**
* Returns the version of the dependency based on the custom artifact ID.
*
* @return the version of the dependency
*/
public String getVersion() {
return CustomNameplatesProperties.getValue(customArtifactID);
}
@@ -390,6 +419,12 @@ public enum Dependency {
return s.replace("{}", ".");
}
/**
* Returns the filename for the dependency's JAR file, optionally with a classifier.
*
* @param classifier the classifier for the JAR (e.g., "sources" or "javadoc")
* @return the filename for the JAR
*/
public String getFileName(String classifier) {
String name = customArtifactID.toLowerCase(Locale.ROOT).replace('_', '-');
String extra = classifier == null || classifier.isEmpty()
@@ -398,6 +433,11 @@ public enum Dependency {
return name + "-" + this.getVersion() + extra + ".jar";
}
/**
* Returns the Maven repository path for the dependency.
*
* @return the Maven repository path
*/
String getMavenRepoPath() {
return String.format(MAVEN_FORMAT,
rewriteEscaping(groupId).replace(".", "/"),
@@ -408,6 +448,11 @@ public enum Dependency {
);
}
/**
* Returns the list of relocations for the dependency.
*
* @return a list of {@link Relocation} objects
*/
public List<Relocation> getRelocations() {
return this.relocations;
}
@@ -426,6 +471,11 @@ public enum Dependency {
}
}
/**
* Gets the repo
*
* @return the repo
*/
@Nullable
public String getRepo() {
return repo;
@@ -30,18 +30,20 @@ package net.momirealms.customnameplates.common.dependency;
*/
public class DependencyDownloadException extends Exception {
public DependencyDownloadException() {
}
/**
* Constructs a new DependencyDownloadException with the specified detail message.
*
* @param message the detail message, which provides additional information about the error
*/
public DependencyDownloadException(String message) {
super(message);
}
public DependencyDownloadException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new DependencyDownloadException with the specified cause.
*
* @param cause the cause of the exception, which can be retrieved later with {@link Throwable#getCause()}
*/
public DependencyDownloadException(Throwable cause) {
super(cause);
}
@@ -61,6 +61,11 @@ public class DependencyManagerImpl implements DependencyManager {
private final Executor loadingExecutor;
private final NameplatesPlugin plugin;
/**
* Constructs a DependencyManagerImpl instance
*
* @param plugin plugin
*/
public DependencyManagerImpl(NameplatesPlugin plugin) {
this.plugin = plugin;
this.registry = new DependencyRegistry();
@@ -32,6 +32,12 @@ import com.google.gson.JsonElement;
*/
public class DependencyRegistry {
/**
* Check if the dependency should be automatically loaded
*
* @param dependency dependency
* @return should be automatically loaded or not
*/
public boolean shouldAutoLoad(Dependency dependency) {
return switch (dependency) {
// all used within 'isolated' classloaders, and are therefore not
@@ -41,6 +47,11 @@ public class DependencyRegistry {
};
}
/**
* Checks if gson is relocated
*
* @return relocated or not
*/
@SuppressWarnings("ConstantConditions")
public static boolean isGsonRelocated() {
return JsonElement.class.getName().startsWith("net.momirealms");
@@ -58,5 +69,4 @@ public class DependencyRegistry {
private static boolean slf4jPresent() {
return classExists("org.slf4j.Logger") && classExists("org.slf4j.LoggerFactory");
}
}
@@ -66,6 +66,11 @@ public enum DependencyRepository {
this.id = id;
}
/**
* Gets the url of this repo
*
* @return the url
*/
public String getUrl() {
return url;
}
@@ -17,16 +17,23 @@
package net.momirealms.customnameplates.common.event;
import net.kyori.adventure.text.Component;
/**
* Interface representing an event or task that can be cancelled.
* This interface defines methods to check and set the cancellation state of the event or task.
*/
public interface Cancellable {
public interface CommandFeedbackEvent<C> extends NameplatesEvent, Cancellable {
/**
* Gets the current cancelled state of the event or task.
*
* @return true if the event or task has been cancelled, false otherwise.
*/
boolean cancelled();
@Param(0)
C sender();
@Param(1)
String key();
@Param(2)
Component message();
/**
* Sets the cancelled state of the event or task.
*
* @param cancelled a boolean indicating whether the event is cancelled
*/
void cancelled(final boolean cancelled);
}
@@ -0,0 +1,53 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.event;
import net.kyori.adventure.text.Component;
/**
* An event that represents feedback generated by a command execution.
* This event contains the sender of the command, the associated key, and the feedback message.
*/
public interface CommandFeedbackEvent<C> extends NameplatesEvent, Cancellable {
/**
* Gets the sender of the command that triggered this event.
*
* @return the sender (e.g., player or entity) of the command.
*/
@Param(0)
C sender();
/**
* Gets the key associated with the feedback message.
* This key may be used to identify the context or specific type of feedback.
*
* @return the key for the feedback message.
*/
@Param(1)
String key();
/**
* Gets the feedback message that will be sent in response to the command.
* The message is represented by a {@link Component}, which allows for rich text formatting.
*
* @return the feedback message to be displayed or logged.
*/
@Param(2)
Component message();
}
@@ -0,0 +1,129 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.common.event;
import net.momirealms.customnameplates.common.event.bus.EventBus;
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
import java.util.OptionalInt;
/**
* Interface for managing and dispatching events within the Nameplates plugin system.
* <p>
* This interface provides methods to subscribe to events, dispatch events, and interact with the underlying
* {@link EventBus}. It allows plugins to register subscribers for specific events and manage the event lifecycle.
* </p>
*/
public interface EventManager {
/**
* A static inner class that holds the singleton instance of {@link EventManager}.
* This ensures that the {@link EventManager} is initialized only once.
*/
class SingletonHolder {
private static EventManager INSTANCE = null;
}
/**
* Creates and returns the singleton instance of {@link EventManager}.
* <p>
* This method ensures that only one instance of the {@link EventManager} is created during the lifecycle
* of the plugin. If the instance does not exist, it initializes the {@link EventManager} using the provided
* {@link NameplatesPlugin}.
* </p>
*
* @param plugin the {@link NameplatesPlugin} instance to be used for initializing the event manager
* @return the singleton instance of {@link EventManager}
*/
static EventManager create(NameplatesPlugin plugin) {
if (SingletonHolder.INSTANCE == null) {
SingletonHolder.INSTANCE = new EventManagerImpl(plugin);
}
return SingletonHolder.INSTANCE;
}
/**
* Subscribes a {@link EventSubscriber} to an event type.
* <p>
* This method allows subscribing a listener (subscriber) to a specific event type. The subscriber will be notified
* whenever the event is dispatched.
* </p>
*
* @param <T> the type of event to subscribe to
* @param event the {@link Class} object representing the event type
* @param subscriber the {@link EventSubscriber} that will handle the event
* @return an {@link EventSubscription} representing the subscription
*/
<T extends NameplatesEvent> EventSubscription<T> subscribe(Class<T> event, EventSubscriber<? super T> subscriber);
/**
* Subscribes a {@link EventSubscriber} to an event type with a custom event configuration.
* <p>
* This method allows subscribing a listener (subscriber) to a specific event type with additional configuration
* settings for the event. The subscriber will be notified based on the provided configuration when the event is
* dispatched.
* </p>
*
* @param <T> the type of event to subscribe to
* @param event the {@link Class} object representing the event type
* @param config the {@link EventConfig} containing additional event configuration
* @param subscriber the {@link EventSubscriber} that will handle the event
* @return an {@link EventSubscription} representing the subscription
*/
<T extends NameplatesEvent> EventSubscription<T> subscribe(Class<T> event, EventConfig config, EventSubscriber<? super T> subscriber);
/**
* Dispatches an event of the specified class with the provided parameters.
* <p>
* This method triggers the event, notifying all subscribers of the event. The event is dispatched synchronously
* to all registered subscribers.
* </p>
*
* @param eventClass the {@link Class} object representing the event type
* @param params the parameters to pass to the event
* @return the dispatched {@link NameplatesEvent}
*/
NameplatesEvent dispatch(Class<? extends NameplatesEvent> eventClass, Object... params);
/**
* Dispatches an event of the specified class with the provided order and parameters.
* <p>
* This method allows dispatching the event with an optional order. The order is used to prioritize events,
* allowing certain events to be processed before others. If the order is not provided, the event will be dispatched
* without any specific order.
* </p>
*
* @param eventClass the {@link Class} object representing the event type
* @param order the optional {@link OptionalInt} specifying the order of the event
* @param params the parameters to pass to the event
* @return the dispatched {@link NameplatesEvent}
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
NameplatesEvent dispatch(Class<? extends NameplatesEvent> eventClass, OptionalInt order, Object... params);
/**
* Retrieves the underlying event bus that handles event dispatching and subscriptions.
* <p>
* The {@link EventBus} is responsible for managing the lifecycle of events, including dispatching and subscribing
* to events. This method allows direct access to the {@link EventBus}.
* </p>
*
* @return the underlying {@link EventBus} used by the event manager
*/
EventBus<?> getEventBus();
}
Loaded 100 of 265 files, more files were not shown because too many files have changed in this diff. Show more