Compare commits

...
120 Commits
Author SHA1 Message Date
XiaoMoMi f5d2d6a0bc 1.20.3 support 2024-11-02 20:12:38 +08:00
XiaoMoMi 7d6fba25e6 bypass other names 2024-10-30 20:00:45 +08:00
XiaoMoMi fcb045e0c8 Update gradle.properties 2024-10-28 20:54:37 +08:00
XiaoMoMi df098a053e update config version to 32 2024-10-27 01:22:11 +08:00
XiaoMoMi 2958b4e1db Merge pull request #49 from BitByLogics/main
Add creative-central resourcepack integration support
2024-10-25 21:25:33 +08:00
Justin 84a37ed619 Add creative-central resourcepack integration support 2024-10-24 22:58:27 -04:00
XiaoMoMi f66c800f3a Update NameplatesExtraExpansion.java 2024-10-24 19:52:17 +08:00
XiaoMoMi 0fb4ae37e4 3.0.6 2024-10-24 03:54:07 +08:00
XiaoMoMi 9a9add1f03 fix reset 2024-10-22 00:12:23 +08:00
XiaoMoMi 5d48530eb6 3.0.5 2024-10-21 03:08:51 +08:00
XiaoMoMi f5e33f5647 3.0.5 2024-10-18 23:43:29 +08:00
XiaoMoMi ffdc7c49ce 3.0.5 2024-10-18 23:43:17 +08:00
XiaoMoMi 46d922ab15 fix folia again 2024-10-15 01:58:53 +08:00
XiaoMoMi aee8ebf9ae increase the delay for folia 2024-10-15 01:40:11 +08:00
XiaoMoMi be086cd91f folia fix 2024-10-15 01:10:25 +08:00
XiaoMoMi 0b96cefcf2 Update BukkitCNPlayer.java 2024-10-14 03:51:13 +08:00
XiaoMoMi 8867b25307 3.0.3 2024-10-13 21:54:40 +08:00
XiaoMoMi bd6caee58f update libs 2024-10-12 21:47:58 +08:00
XiaoMoMi d0b057b391 Update BukkitCustomNameplates.java 2024-10-11 23:35:45 +08:00
XiaoMoMi 2e03248555 3.0.2 2024-10-11 23:31:02 +08:00
XiaoMoMi 5898d8e3d4 3.0.2 2024-10-11 23:11:37 +08:00
XiaoMoMi 8bcb7d3380 to fix teams 2024-10-11 05:30:24 +08:00
XiaoMoMi 59dda019d8 Update PlayerListener.java 2024-10-11 03:19:42 +08:00
XiaoMoMi 7512a97461 fix teleport 2024-10-11 03:15:44 +08:00
XiaoMoMi 63075ad1bb 3.0.1 2024-10-11 02:53:43 +08:00
XiaoMoMi 2c9bdc662a added nametag module 2024-10-10 17:09:28 +08:00
XiaoMoMi 545826801a Update HasBubbleRequirement.java 2024-10-10 16:01:10 +08:00
XiaoMoMi 26c30b8bab Merge pull request #47 from thomasz05/main
Fix HasNameplateRequirement to return false if nameplate module is di…
2024-10-10 15:59:19 +08:00
thomasz_05 c022319b67 Fix HasNameplateRequirement to return false if nameplate module is disabled 2024-10-09 23:41:09 +02:00
XiaoMoMi 37da5df7e6 beta5 2024-10-09 23:17:41 +08:00
XiaoMoMi aa919d18e0 Fix bugs 2024-10-09 22:33:22 +08:00
XiaoMoMi 7eb3296294 beta4 2024-10-09 21:38:05 +08:00
XiaoMoMi d84c9f7031 new event 2024-10-09 00:22:21 +08:00
XiaoMoMi ec840036ac Update PlaceholderManagerImpl.java 2024-10-08 23:23:15 +08:00
XiaoMoMi a168cb8591 modules 2024-10-08 23:14:33 +08:00
XiaoMoMi 8856831a94 code clean up 2024-10-08 22:53:51 +08:00
XiaoMoMi a387cf5127 beta3 2024-10-08 22:26:48 +08:00
XiaoMoMi 6b2bbea6e1 Update build.gradle.kts 2024-10-08 05:46:12 +08:00
XiaoMoMi 67732ecf76 update default configs 2024-10-08 05:39:58 +08:00
XiaoMoMi f361ad1015 remove color 2024-10-08 05:26:29 +08:00
XiaoMoMi 57a1593315 time24 2024-10-08 04:07:09 +08:00
XiaoMoMi a424c3345a fix 2024-10-08 03:32:11 +08:00
XiaoMoMi 047852eed9 beta2 2024-10-08 00:51:42 +08:00
XiaoMoMi 5d2d3e0933 Improve interval system 2024-10-07 22:45:12 +08:00
XiaoMoMi efe90b95b5 Update PlaceholderManagerImpl.java 2024-10-07 22:09:45 +08:00
XiaoMoMi cad0e07411 beta2 2024-10-07 22:08:37 +08:00
XiaoMoMi f6de779090 improve spectator mode 2024-10-07 17:23:57 +08:00
XiaoMoMi 5df341b2a1 Update AdvanceManagerImpl.java 2024-10-07 02:44:23 +08:00
XiaoMoMi 2ba7ad95ba TTF 2024-10-07 01:28:26 +08:00
XiaoMoMi 4b2ddf6cd1 Fix build 2024-10-06 23:12:48 +08:00
XiaoMoMi e392e0fd4d Update AdventureHelper.java 2024-10-06 22:49:49 +08:00
XiaoMoMi 10206e8b2a fix build 2024-10-06 22:48:21 +08:00
XiaoMoMi f935a61958 improve shaders 2024-10-06 22:42:27 +08:00
XiaoMoMi 844e53ff1a API 2024-10-06 01:25:48 +08:00
XiaoMoMi 7209b9772b Improve bubbles 2024-10-05 23:11:55 +08:00
XiaoMoMi 3aa7e5c012 3.0 2024-10-05 22:42:28 +08:00
XiaoMoMi d8324da1d9 Update README.md 2024-09-20 04:27:15 +08:00
XiaoMoMi f66bc23037 Fixed send delay 2024-09-20 04:24:04 +08:00
XiaoMoMi 425a08a57a 2.4.8.1 2024-08-31 02:56:40 +08:00
XiaoMoMi f597e584ee add prefix to team 2024-08-30 15:58:20 +08:00
XiaoMoMi 886a3c53a3 2.4.8 2024-08-30 15:40:43 +08:00
XiaoMoMi 90b07517a7 Update DependencyManagerImpl.java 2024-08-29 22:00:34 +08:00
XiaoMoMi 4ef7da87b4 Update ResourcePackManagerImpl.java 2024-08-15 01:53:20 +08:00
XiaoMoMi a5fd4f237e Fix shaders on 1.20.5+ 2024-08-13 16:49:25 +08:00
XiaoMoMi 5046372177 2.4.6-pre-1 2024-08-11 20:28:22 +08:00
XiaoMoMi df86e4bc33 Merge pull request #38 from DrZoddiak/feature-ignore
[Feature] Support Ignoring for Chat Bubbles
2024-08-10 01:01:07 +08:00
Jesse McKee b5e83ca984 Implements ignoring bubbles
Allows for plugins that allow for ignoring to also ignore chat bubbles.

Carbon was given special attention for this PR, but other plugins will maintain prior behavior.
2024-08-08 01:06:33 -05:00
XiaoMoMi 04bb10cb3d Merge pull request #37 from DrZoddiak/fix-channel-mode
Fix channel-mode
2024-08-08 13:46:41 +08:00
Jesse McKee e7371cc02a Fix JOINED channel-mode for CarbonChatProvider
#selectedChannel only gets the channel current selected by the player if it exists. If a user does NOT select a channel, and is instead put into a default channel, the result is still `null`.

This PR provides a fallback value for channels in this case.
2024-08-08 00:27:00 -05:00
Jesse McKee bee0b26a9f Fix CAN_JOIN channel-mode
the method in question requires 1 argument, and was being passed 0. This error was being swallowed and not shown in console, so it was not immediately obvious.

Reading the JD for #invoke
`If the underlying method is static, then the specified obj argument is ignored. It may be null.`

So in order to pass the arg required, and because the method is indeed static, the first parameter is now null.
2024-08-08 00:21:05 -05:00
XiaoMoMi 343c0e5cb0 Update build.gradle.kts 2024-08-04 16:48:29 +08:00
XiaoMoMi 81d3a888b8 2.4.4 2024-08-04 16:48:02 +08:00
XiaoMoMi 58e16e5376 Fixed nms on 1.18.2 2024-07-27 17:17:42 +08:00
XiaoMoMi cc8c3d6bcd 2.4.2 2024-07-25 22:41:15 +08:00
XiaoMoMi 3000b26bfa Fix async events 2024-07-03 15:56:47 +08:00
XiaoMoMi a800481574 Update NameplateManagerImpl.java 2024-07-03 15:23:46 +08:00
XiaoMoMi 82350ac0c4 Fix some issues 2024-07-03 15:09:39 +08:00
XiaoMoMi 35edd85434 Update en.yml 2024-06-28 22:51:15 +08:00
XiaoMoMi 99bfc28be8 1.21 support 2024-06-28 02:52:20 +08:00
XiaoMoMi 5ee27c126c fix shader on 1.20.5+ 2024-06-28 01:12:39 +08:00
XiaoMoMi 5282d5e8a7 use NMS to send bossbar 2024-06-28 00:21:19 +08:00
XiaoMoMi 0f7a72bf1e Merge pull request #33 from relpia/main
Create kr.yml
2024-06-26 19:45:58 +08:00
XiaoMoMi b36d0c23e1 some changes 2024-06-24 00:14:44 +08:00
Horibin f8219659c4 Add files via upload 2024-06-22 13:01:28 +09:00
XiaoMoMi eb730c8631 Merge pull request #32 from Vondri/patch-2
Create pl.yml
2024-05-25 17:03:59 +08:00
Vondri 12b8b74031 Create pl.yml
Translation for polish
2024-05-18 00:46:15 +02:00
XiaoMoMi 365aae10f5 2.3.3.9 2024-05-07 22:34:39 +08:00
XiaoMoMi 5e299bb0d4 Update build logics 2024-05-04 05:10:53 +08:00
XiaoMoMi 79a0892b09 [Update] Updated dependencies 2024-04-23 03:43:07 +08:00
XiaoMoMi a8bc4d8de5 update shaders 2024-04-22 01:14:48 +08:00
XiaoMoMi 6276d27d57 Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2024-04-16 23:39:06 +08:00
XiaoMoMi 096e6330d6 2.3.3.8 2024-04-16 23:39:01 +08:00
XiaoMoMi e41686aa31 Merge pull request #30 from Schroddinger/release
Tweaks to Spanish translation
2024-04-16 02:39:05 +08:00
Schroddinger 590b26ac2a Tweaks to Spanish translation 2024-04-14 11:19:13 -05:00
XiaoMoMi a7dc0db15d rename language files 2024-04-14 20:19:37 +08:00
XiaoMoMi c9250fea13 Merge pull request #28 from jhqwqmc/main
small changes
2024-04-07 21:33:26 +08:00
jhqwqmc fa914d52a2 del time-24 2024-04-07 21:12:10 +08:00
jhqwqmc efbf2d3b64 Update config file 2024-04-07 21:03:01 +08:00
jhqwqmc 40672aefb4 small changes
Add a 24-hour time variable
Fix weather detection issue
2024-04-07 21:00:50 +08:00
XiaoMoMi 8fb4b8317d 2.3.3.7
修复旧版颜色相关问题
2024-04-07 01:27:11 +08:00
XiaoMoMi e68a333527 Fix minimessage alias 2024-03-31 03:16:51 +08:00
XiaoMoMi 53317c3e4b better bold support 2024-03-17 17:42:12 +08:00
XiaoMoMi c2c1b703b7 2.3.3.6 2024-03-17 16:26:26 +08:00
XiaoMoMi abcece373f 2.3.3.6 2024-03-13 19:19:18 +08:00
XiaoMoMi be8cf27f37 fix bold 2024-03-10 08:13:34 +08:00
XiaoMoMi 6fafb85cec 2.3.3.3 2024-03-07 23:51:32 +08:00
XiaoMoMi d18bf83ecb Update FoliaSchedulerImpl.java 2024-03-04 15:55:59 +08:00
XiaoMoMi 2c8aad7a75 disguise support 2024-02-27 16:47:36 +08:00
XiaoMoMi 9e8e57c6df adjust priority 2024-02-27 02:55:40 +08:00
XiaoMoMi 1c433d1891 update to gradle 8.6 2024-02-26 12:48:21 +08:00
XiaoMoMi 6e77eb55d0 Update README.md 2024-02-25 01:39:42 +08:00
XiaoMoMi 3afa1bfb58 compatibility with Libsdisguises 2024-02-25 00:50:03 +08:00
XiaoMoMi 39e9d40e3e small changes 2024-02-24 21:16:17 +08:00
XiaoMoMi 2e90d02166 fix some minor issues 2024-02-22 20:18:16 +08:00
XiaoMoMi 9d88ead4e3 remap libs 2024-02-20 04:59:14 +08:00
XiaoMoMi 810b8f0593 version number 2024-02-18 03:23:44 +08:00
XiaoMoMi 930cdf8c00 Fix concurrent modification 2024-02-18 03:16:33 +08:00
XiaoMoMi a26e6dc784 optimize imports 2024-02-10 18:44:22 +08:00
XiaoMoMi e450b1429d channel mode 2024-02-04 18:43:55 +08:00
XiaoMoMi 7811cea007 Update gradle.properties 2024-02-03 03:51:39 +08:00
892 changed files with 36230 additions and 22275 deletions

No files matched your search

+22 -26
View File
@@ -1,41 +1,37 @@
# 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>
[![Scc Count Badge](https://sloc.xyz/github/Xiao-MoMi/Custom-Nameplates/?category=codes)](https://github.com/Xiao-MoMi/Custom-Nameplates/)
![Code Size](https://img.shields.io/github/languages/code-size/Xiao-MoMi/Custom-Nameplates)
![bStats Servers](https://img.shields.io/bstats/servers/16649)
![bStats Players](https://img.shields.io/bstats/players/16649)
![GitHub](https://img.shields.io/github/license/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/" alt="GitBook">
<img src="https://img.shields.io/badge/docs-gitbook-brightgreen" alt="Gitbook"/>
</a>
CustomNameplates is a Paper plugin that provides unlimited customization for nametags, bossbars, actionbars and chat bubbles.
## How to build
### Windows
#### Command Line
Install JDK 17 and set the JDK installation path to JAVA_HOME as an environment variable.\
Start powershell and change directory to the project folder.\
Execute ".\gradlew build" and get the jar at /target/CustomNameplates-universe-version.jar.
Install JDK 17 & 21. \
Start terminal and change directory to the project folder.\
Execute ".\gradlew build" and get the artifact under /target folder
#### IDE
Import the project and execute gradle build action.
##### About Proxy
If you are using a proxy, configurate the proxy in gradle.properties. Otherwise comment the lines in gradle.properties.
Import the project and execute gradle build action. \
Get the artifact under /target folder
## Support the developer
Polymart: https://polymart.org/resource/customnameplates.2543 \
Afdian: https://afdian.net/@xiaomomi
Afdian: https://afdian.com/@xiaomomi
## Use CustomNameplates API
## CustomNameplates API
### Maven
```
```html
<repositories>
<repository>
<id>jitpack</id>
@@ -43,37 +39,37 @@ Afdian: https://afdian.net/@xiaomomi
</repository>
</repositories>
```
```
```html
<dependencies>
<dependency>
<groupId>com.github.Xiao-MoMi</groupId>
<artifactId>Custom-Nameplates</artifactId>
<version>{LATEST}</version>
<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:{LATEST}'
compileOnly 'com.github.Xiao-MoMi:Custom-Nameplates:{VERSION}'
}
```
### Gradle (Kotlin)
```
```kotlin
repositories {
maven("https://jitpack.io/")
}
```
```
```kotlin
dependencies {
compileOnly("com.github.Xiao-MoMi:Custom-Nameplates:{LATEST}")
compileOnly("com.github.Xiao-MoMi:Custom-Nameplates:{VERSION}")
}
```
+52 -4
View File
@@ -1,12 +1,60 @@
plugins {
id("io.github.goooler.shadow") version "8.1.8"
id("maven-publish")
}
repositories {
maven("https://jitpack.io/")
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://oss.sonatype.org/content/repositories/snapshots")
}
dependencies {
compileOnly("dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
implementation(project(":common"))
implementation("net.kyori:adventure-api:4.15.0")
// 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"]}")
// 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")
// GSON
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(17)
dependsOn(tasks.clean)
}
tasks {
shadowJar {
archiveClassifier = ""
archiveFileName = "CustomNameplates-${rootProject.properties["project_version"]}.jar"
relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
relocate("dev.dejvokep", "net.momirealms.customnameplates.libraries")
}
}
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
groupId = "net.momirealms"
artifactId = "CustomNameplates"
version = rootProject.version.toString()
artifact(tasks.shadowJar)
}
}
}
Binary file not shown.
@@ -0,0 +1,514 @@
/*
* 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.api;
import io.netty.channel.Channel;
import net.momirealms.customnameplates.api.feature.Feature;
import net.momirealms.customnameplates.api.feature.TimeStampData;
import net.momirealms.customnameplates.api.feature.tag.TeamView;
import net.momirealms.customnameplates.api.network.Tracker;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import net.momirealms.customnameplates.api.placeholder.PlayerPlaceholder;
import net.momirealms.customnameplates.api.placeholder.RelationalPlaceholder;
import net.momirealms.customnameplates.api.placeholder.SharedPlaceholder;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.storage.data.PlayerData;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
public abstract class AbstractCNPlayer implements CNPlayer {
protected final CustomNameplates plugin;
protected final Channel channel;
protected Object player;
private boolean isLoaded = false;
private boolean tempPreviewing = false;
private boolean toggleablePreviewing = false;
private String equippedNameplate;
private String equippedBubble;
private final TeamView teamView = new TeamView();
private final Map<Integer, TimeStampData<String>> cachedValues = new ConcurrentHashMap<>();
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>();
private final Map<Requirement, TimeStampData<Boolean>> cachedRequirements = new ConcurrentHashMap<>();
private final Map<Requirement, WeakHashMap<CNPlayer, TimeStampData<Boolean>>> cachedRelationalRequirements = new ConcurrentHashMap<>();
private final Set<Feature> activeFeatures = new CopyOnWriteArraySet<>();
private final Map<Placeholder, Set<Feature>> placeholder2Features = new ConcurrentHashMap<>();
private final Map<Feature, Set<Placeholder>> feature2Placeholders = new ConcurrentHashMap<>();
private final Map<CNPlayer, Tracker> trackers = Collections.synchronizedMap(new WeakHashMap<>());
protected AbstractCNPlayer(CustomNameplates plugin, Channel channel) {
this.plugin = plugin;
this.channel = channel;
}
@Override
public List<Placeholder> activePlaceholdersToRefresh() {
Placeholder[] activePlaceholders = activePlaceholders();
List<Placeholder> placeholderWithChildren = new ArrayList<>();
for (Placeholder placeholder : activePlaceholders) {
childrenFirstList(placeholder, placeholderWithChildren);
}
return placeholderWithChildren.stream().distinct().toList();
}
@Override
public void forceUpdatePlaceholders(Set<Placeholder> placeholders, Set<CNPlayer> others) {
if (placeholders.isEmpty()) return;
List<Placeholder> placeholderWithChildren = new ArrayList<>();
for (Placeholder placeholder : placeholders) {
childrenFirstList(placeholder, placeholderWithChildren);
}
placeholderWithChildren = placeholderWithChildren.stream().distinct().toList();
for (Placeholder placeholder : placeholderWithChildren) {
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
TimeStampData<String> value = getValue(placeholder);
if (value == null) {
value = new TimeStampData<>(playerPlaceholder.request(this), MainTask.getTicks(), true);
setValue(placeholder, value);
continue;
}
if (value.ticks() != MainTask.getTicks()) {
String newValue = playerPlaceholder.request(this);
value.updateTicks(!value.data().equals(newValue));
value.data(newValue);
}
} else if (placeholder instanceof RelationalPlaceholder relational) {
for (CNPlayer player : others) {
TimeStampData<String> value = getRelationalValue(placeholder, player);
if (value == null) {
value = new TimeStampData<>(relational.request(this, player), MainTask.getTicks(), true);
setRelationalValue(placeholder, player, value);
continue;
}
if (value.ticks() != MainTask.getTicks()) {
String newValue = relational.request(this, player);
value.updateTicks(!value.data().equals(newValue));
value.data(newValue);
}
}
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
TimeStampData<String> value = getValue(placeholder);
if (value == null) {
String latest;
if (MainTask.hasRequested(sharedPlaceholder.countId())) {
latest = sharedPlaceholder.getLatestValue();
} else {
latest = sharedPlaceholder.request();
}
value = new TimeStampData<>(latest, MainTask.getTicks(), true);
setValue(placeholder, value);
continue;
}
if (value.ticks() != MainTask.getTicks()) {
String latest;
if (MainTask.hasRequested(sharedPlaceholder.countId())) {
latest = sharedPlaceholder.getLatestValue();
} else {
latest = sharedPlaceholder.request();
}
value.updateTicks(!value.data().equals(latest));
value.data(latest);
}
}
}
}
private void childrenFirstList(Placeholder placeholder, List<Placeholder> list) {
if (placeholder.children().isEmpty()) {
list.add(placeholder);
} else {
for (Placeholder child : placeholder.children()) {
childrenFirstList(child, list);
}
list.add(placeholder);
}
}
private void parentLastList(Placeholder placeholder, List<Placeholder> list) {
if (placeholder.parents().isEmpty()) {
list.add(placeholder);
} else {
list.add(placeholder);
for (Placeholder parent : placeholder.parents()) {
parentLastList(parent, list);
}
}
}
public void reload() {
cachedValues.clear();
cachedRelationalValues.clear();
cachedRequirements.clear();
cachedRelationalRequirements.clear();
activeFeatures.clear();
placeholder2Features.clear();
feature2Placeholders.clear();
}
public void setPlayer(Object player) {
this.player = player;
}
@Override
public Channel channel() {
return channel;
}
@Override
public Set<Feature> activeFeatures(Placeholder placeholder) {
return placeholder2Features.getOrDefault(placeholder, Collections.emptySet());
}
@Override
public Object player() {
return player;
}
public void setLoaded(boolean loaded) {
isLoaded = loaded;
}
public void setTempPreviewing(boolean previewing) {
this.tempPreviewing = previewing;
}
@Override
public boolean isTempPreviewing() {
return tempPreviewing;
}
public void setToggleablePreviewing(boolean previewing) {
this.toggleablePreviewing = previewing;
}
@Override
public boolean isToggleablePreviewing() {
return toggleablePreviewing;
}
@Override
public boolean isLoaded() {
return isLoaded;
}
@Override
public void addFeature(Feature feature) {
activeFeatures.add(feature);
Set<Placeholder> allPlaceholders = feature.allPlaceholders();
feature2Placeholders.put(feature, allPlaceholders);
for (Placeholder placeholder : allPlaceholders) {
Set<Feature> featureSet = placeholder2Features.computeIfAbsent(placeholder, k -> new HashSet<>());
featureSet.add(feature);
}
}
@Override
public void removeFeature(Feature feature) {
activeFeatures.remove(feature);
Set<Placeholder> placeholders = feature2Placeholders.remove(feature);
if (placeholders != null) {
for (Placeholder placeholder : placeholders) {
Set<Feature> featureSet = placeholder2Features.get(placeholder);
featureSet.remove(feature);
if (featureSet.isEmpty()) placeholder2Features.remove(placeholder);
}
}
}
@Override
public void setValue(Placeholder placeholder, TimeStampData<String> value) {
cachedValues.put(placeholder.countId(), value);
}
@Override
public boolean setValue(Placeholder placeholder, String value) {
TimeStampData<String> previous = cachedValues.get(placeholder.countId());
int currentTicks = MainTask.getTicks();
boolean changed = false;
if (previous != null) {
if (previous.ticks() == currentTicks) {
return false;
}
String data = previous.data();
if (!data.equals(value)) {
changed = true;
previous.data(value);
previous.updateTicks(true);
}
} else {
changed= true;
previous = new TimeStampData<>(value, currentTicks, true);
cachedValues.put(placeholder.countId(), previous);
}
return changed;
}
@Override
public void setRelationalValue(Placeholder placeholder, CNPlayer another, TimeStampData<String> value) {
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
map.put(another, value);
}
@Override
public boolean setRelationalValue(Placeholder placeholder, CNPlayer another, String value) {
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
TimeStampData<String> previous = map.get(another);
int currentTicks = MainTask.getTicks();
boolean changed = false;
if (previous != null) {
if (previous.ticks() == currentTicks) {
return false;
}
String data = previous.data();
if (!data.equals(value)) {
changed = true;
previous.data(value);
previous.updateTicks(true);
}
} else {
changed= true;
previous = new TimeStampData<>(value, currentTicks, true);
map.put(another, previous);
}
return changed;
}
@Override
public @NotNull String getData(Placeholder placeholder) {
return Optional.ofNullable(cachedValues.get(placeholder.countId())).map(TimeStampData::data).orElse(placeholder.id());
}
@Override
public TimeStampData<String> getValue(Placeholder placeholder) {
return cachedValues.get(placeholder.countId());
}
@Override
public @NotNull String getRelationalData(Placeholder placeholder, CNPlayer another) {
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
if (map == null) {
return placeholder.id();
}
return Optional.ofNullable(map.get(another)).map(TimeStampData::data).orElse(placeholder.id());
}
@Override
public TimeStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another) {
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
if (map == null) {
return null;
}
return map.get(another);
}
@Override
public Placeholder[] activePlaceholders() {
HashSet<Placeholder> placeholders = new HashSet<>();
for (Feature feature : activeFeatures) {
placeholders.addAll(feature.activePlaceholders());
}
return placeholders.toArray(new Placeholder[0]);
}
@Override
public boolean isMet(Requirement[] requirements) {
int currentTicks = MainTask.getTicks();
for (Requirement requirement : requirements) {
TimeStampData<Boolean> data = cachedRequirements.get(requirement);
if (data != null) {
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
if (!data.data()) {
return false;
}
} else {
boolean satisfied = requirement.isSatisfied(this, this);
data.updateTicks(false);
data.data(satisfied);
if (!satisfied) {
return false;
}
}
} else {
boolean satisfied = requirement.isSatisfied(this, this);
data = new TimeStampData<>(satisfied, currentTicks, true);
cachedRequirements.put(requirement, data);
if (!satisfied) {
return false;
}
}
}
return true;
}
@Override
public boolean isMet(CNPlayer another, Requirement[] requirements) {
int currentTicks = MainTask.getTicks();
for (Requirement requirement : requirements) {
WeakHashMap<CNPlayer, TimeStampData<Boolean>> innerMap = cachedRelationalRequirements.computeIfAbsent(requirement, k -> new WeakHashMap<>());
TimeStampData<Boolean> data = innerMap.get(another);
if (data != null) {
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
if (!data.data()) {
return false;
}
} else {
boolean satisfied = requirement.isSatisfied(this, another);
data.updateTicks(false);
data.data(satisfied);
if (!satisfied) {
return false;
}
}
} else {
boolean satisfied = requirement.isSatisfied(this, another);
data = new TimeStampData<>(satisfied, currentTicks, true);
innerMap.put(another, data);
if (!satisfied) {
return false;
}
}
}
return true;
}
@Override
public Tracker addPlayerToTracker(CNPlayer another) {
Tracker tracker = trackers.get(another);
if (tracker != null) {
return tracker;
}
tracker = new Tracker(another);
trackers.put(another, tracker);
for (Placeholder placeholder : activePlaceholders()) {
if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
String value = relationalPlaceholder.request(this, another);
setRelationalValue(placeholder, another, value);
}
}
return tracker;
}
@Override
public void removePlayerFromTracker(CNPlayer another) {
trackers.remove(another);
}
@Override
public Set<CNPlayer> nearbyPlayers() {
return new HashSet<>(trackers.keySet());
}
@Override
public void trackPassengers(CNPlayer another, int... passengers) {
Tracker tracker = trackers.get(another);
if (tracker != null) {
for (int passenger : passengers) {
tracker.addPassengerID(passenger);
}
}
}
@Override
public void untrackPassengers(CNPlayer another, int... passengers) {
Optional.ofNullable(trackers.get(another)).ifPresent(tracker -> {
for (int passenger : passengers) {
tracker.removePassengerID(passenger);
}
});
}
@Override
public Set<Integer> getTrackedPassengerIds(CNPlayer another) {
return Optional.ofNullable(trackers.get(another)).map(Tracker::getPassengerIDs).orElse(new HashSet<>());
}
@Override
public Tracker getTracker(CNPlayer another) {
return trackers.get(another);
}
@Override
public String equippedBubble() {
if (equippedNameplate == null) return "none";
return equippedBubble;
}
@Override
public boolean equippedBubble(String equippedBubble) {
if (!isLoaded()) return false;
if (!equippedBubble.equals(this.equippedBubble)) {
this.equippedBubble = equippedBubble;
}
return true;
}
@Override
public String equippedNameplate() {
if (equippedNameplate == null) return "none";
return equippedNameplate;
}
@Override
public boolean equippedNameplate(String equippedNameplate) {
if (!isLoaded()) return false;
if (!equippedNameplate.equals(this.equippedNameplate)) {
this.equippedNameplate = equippedNameplate;
}
return true;
}
@Override
public void save() {
plugin.getStorageManager().dataSource().updatePlayerData(PlayerData.builder()
.uuid(uuid())
.nameplate(equippedNameplate())
.bubble(equippedBubble())
.previewTags(isToggleablePreviewing())
.build(), plugin.getScheduler().async());
}
@Override
public TeamView teamView() {
return teamView;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
AbstractCNPlayer that = (AbstractCNPlayer) object;
return entityID() == that.entityID() && uuid().equals(that.uuid());
}
@Override
public int hashCode() {
return entityID();
}
}
@@ -0,0 +1,404 @@
/*
* 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.api;
import io.netty.channel.Channel;
import net.momirealms.customnameplates.api.feature.Feature;
import net.momirealms.customnameplates.api.feature.TimeStampData;
import net.momirealms.customnameplates.api.feature.tag.TeamView;
import net.momirealms.customnameplates.api.network.Tracker;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.util.Vector3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public interface CNPlayer {
/**
* Returns the player's name.
*
* @return the player's name
*/
String name();
/**
* Returns the UUID of the player.
*
* @return the player's UUID
*/
UUID uuid();
/**
* Returns the underlying player object (server-side representation).
*
* @return the player object
*/
Object player();
/**
* Returns the channel of the player
*
* @return the channel
*/
Channel channel();
/**
* Returns the entity ID of the player.
*
* @return the entity ID
*/
int entityID();
/**
* Returns the player's current position as a {@link Vector3}.
*
* @return the player's position
*/
Vector3 position();
/**
* Returns the name of the world the player is in.
*
* @return the world name
*/
String world();
/**
* Checks if the player is currently online.
*
* @return true if the player is online, false otherwise
*/
boolean isOnline();
/**
*
* Checks if the player is on spectator mode
*
* @return true if the player is on spectator mode, false otherwise
*/
boolean isSpectator();
/**
* Returns the scale of the player.
*
* @return the player's scale
*/
double scale();
/**
* Checks if the player is crouching.
*
* @return true if the player is crouching, false otherwise
*/
boolean isCrouching();
/**
* Checks if the player has been fully loaded into the system.
*
* @return true if the player is loaded, false otherwise
*/
boolean isLoaded();
/**
* Checks if the player is currently previewing
*
* @return true if the player is previewing, false otherwise
*/
boolean isTempPreviewing();
/**
* Checks if the player has turned their nameplate on
*
* @return true if the player has turned their nameplate on, false otherwise
*/
boolean isToggleablePreviewing();
/**
* Checks if the player has the specified permission.
*
* @param permission the permission to check
* @return true if the player has the permission, false otherwise
*/
boolean hasPermission(String permission);
/**
* Returns the player's current time
*
* @return the player's time
*/
long playerTime();
/**
* Checks if the player is flying.
*
* @return true if the player is flying, false otherwise
*/
boolean isFlying();
/**
* Returns the remaining air level for the player.
*
* @return the player's remaining air
*/
int remainingAir();
/**
* Retrieves the set of features that are actively using the specified placeholder.
*
* @param placeholder the placeholder to check
* @return the set of active features using the placeholder
*/
Set<Feature> activeFeatures(Placeholder placeholder);
/**
* Returns the placeholders that are actively used by the player's features.
*
* @return an array of active placeholders
*/
Placeholder[] activePlaceholders();
/**
* Retrieves the list of placeholders that need to be refreshed based on their refresh intervals.
*
* @return a list of placeholders to refresh
*/
List<Placeholder> activePlaceholdersToRefresh();
/**
* Forces an update for the specified placeholders and relational placeholders with another player.
*
* @param placeholders the placeholders to update
* @param another the players related to the placeholders
*/
void forceUpdatePlaceholders(Set<Placeholder> placeholders, Set<CNPlayer> another);
/**
* Retrieves the cached data for a given placeholder.
*
* @param placeholder the placeholder to retrieve data for
* @return the cached data as a string
*/
@NotNull
String getData(Placeholder placeholder);
/**
* Retrieves the cached {@link TimeStampData} for a given placeholder.
*
* @param placeholder the placeholder to retrieve data for
* @return the cached TickStampData, or null if none exists
*/
@Nullable
TimeStampData<String> getValue(Placeholder placeholder);
/**
* Retrieves the cached relational data between this player and another for a given placeholder.
*
* @param placeholder the relational placeholder
* @param another the other player
* @return the relational data as a string
*/
@NotNull
String getRelationalData(Placeholder placeholder, CNPlayer another);
/**
* Retrieves the cached relational {@link TimeStampData} for a given placeholder.
*
* @param placeholder the relational placeholder
* @param another the other player
* @return the cached relational TickStampData, or null if none exists
*/
@Nullable
TimeStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another);
/**
* Caches the specified {@link TimeStampData} for the given placeholder.
*
* @param placeholder the placeholder to cache
* @param value the value to cache
*/
void setValue(Placeholder placeholder, TimeStampData<String> value);
/**
* Caches the specified value for the given placeholder.
*
* @param placeholder the placeholder to cache
* @param value the value to cache
* @return true if the value was changed, false otherwise
*/
boolean setValue(Placeholder placeholder, String value);
/**
* Caches the specified relational {@link TimeStampData} for a given placeholder and player.
*
* @param placeholder the relational placeholder
* @param another the other player
* @param value the value to cache
*/
void setRelationalValue(Placeholder placeholder, CNPlayer another, TimeStampData<String> value);
/**
* Caches the specified relational value for a given placeholder and player.
*
* @param placeholder the relational placeholder
* @param another the other player
* @param value the value to cache
* @return true if the value was changed, false otherwise
*/
boolean setRelationalValue(Placeholder placeholder, CNPlayer another, String value);
/**
* Adds a feature to the player
*
* @param feature the feature to add
*/
void addFeature(Feature feature);
/**
* Removes a feature from the player.
*
* @param feature the feature to remove
*/
void removeFeature(Feature feature);
/**
* Checks if the player meets the specified requirements.
*
* @param requirements the requirements to check
* @return true if all requirements are met, false otherwise
*/
boolean isMet(Requirement[] requirements);
/**
* Checks if the player meets the specified relational requirements with another player.
*
* @param another the other player
* @param requirements the relational requirements to check
* @return true if all requirements are met, false otherwise
*/
boolean isMet(CNPlayer another, Requirement[] requirements);
/**
* Adds a player to be track this player, creating a tracker for relational placeholders.
*
* @param another the player
* @return the tracker instance
*/
Tracker addPlayerToTracker(CNPlayer another);
/**
* Removes a player from tracking this player.
*
* @param another the player to stop tracking
*/
void removePlayerFromTracker(CNPlayer another);
/**
* Retrieves the set of nearby players tracking this player.
*
* @return the set of nearby players
*/
Set<CNPlayer> nearbyPlayers();
/**
* Adds passenger entities to the tracker for another player.
*
* @param another the player whose passengers to track
* @param passengers the IDs of the passenger entities
*/
void trackPassengers(CNPlayer another, int... passengers);
/**
* Removes passenger entities from the tracker for another player.
*
* @param another the player whose passengers to stop tracking
* @param passengers the IDs of the passenger entities
*/
void untrackPassengers(CNPlayer another, int... passengers);
/**
* Retrieves the IDs of tracked passenger entities for another player.
*
* @param another the viewer
* @return the set of passenger entity IDs
*/
Set<Integer> getTrackedPassengerIds(CNPlayer another);
/**
* Retrieves the IDs of all passenger entities currently associated with this player.
*
* @return the set of passenger entity IDs
*/
Set<Integer> passengers();
/**
* Retrieves the tracker instance for another player.
*
* @param another the viewer
* @return the tracker instance, or null if none exists
*/
Tracker getTracker(CNPlayer another);
/**
* Returns the ID of the currently equipped bubble for the player.
*
* @return the ID of the equipped bubble
*/
String equippedBubble();
/**
* Sets the equipped bubble for the player.
* Operation would fail if player is not loaded.
*
* @param equippedBubble the new bubble ID to equip
* @return success or not
*/
boolean equippedBubble(String equippedBubble);
/**
* Returns the ID of the currently equipped nameplate for the player.
*
* @return the ID of the equipped nameplate
*/
String equippedNameplate();
/**
* Sets the equipped nameplate for the player.
* Operation would fail if player is not loaded.
*
* @param equippedNameplate the new nameplate ID to equip
* @return success or not
*/
boolean equippedNameplate(String equippedNameplate);
/**
* Save the player's current nameplate/bubble to database
*/
void save();
/**
* Get the player's team view
*
* @return team view
*/
TeamView teamView();
}
@@ -0,0 +1,501 @@
/*
* 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.api;
import dev.dejvokep.boostedyaml.YamlDocument;
import dev.dejvokep.boostedyaml.dvs.versioning.BasicVersioning;
import dev.dejvokep.boostedyaml.libs.org.snakeyaml.engine.v2.common.ScalarStyle;
import dev.dejvokep.boostedyaml.libs.org.snakeyaml.engine.v2.nodes.Tag;
import dev.dejvokep.boostedyaml.settings.dumper.DumperSettings;
import dev.dejvokep.boostedyaml.settings.general.GeneralSettings;
import dev.dejvokep.boostedyaml.settings.loader.LoaderSettings;
import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings;
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.common.locale.TranslationManager;
import net.momirealms.customnameplates.common.plugin.CustomNameplatesProperties;
import net.momirealms.customnameplates.common.plugin.config.ConfigLoader;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
public abstract class ConfigManager implements ConfigLoader, Reloadable {
private static YamlDocument MAIN_CONFIG;
public static YamlDocument getMainConfig() {
if (MAIN_CONFIG == null) {
throw new IllegalStateException("Main config not loaded");
}
return MAIN_CONFIG;
}
private static ConfigManager instance;
protected final CustomNameplates plugin;
protected boolean debug;
protected boolean checkUpdate;
protected boolean metrics;
protected boolean nametagModule;
protected boolean actionbarModule;
protected boolean imageModule;
protected boolean bossBarModule;
protected boolean bubbleModule;
protected boolean nameplateModule;
protected boolean backgroundModule;
protected boolean hideTeamNames;
protected int defaultPlaceholderRefreshInterval;
protected int defaultConditionRefreshInterval;
protected int delaySend;
protected boolean catchOtherActionBar;
protected boolean displaySystemChat;
protected int otherActionBarStayTime;
protected String namespace;
protected String font;
protected boolean generateOnStart;
protected char initialChar;
protected String imagePath;
protected String nameplatePath;
protected String bubblePath;
protected String spaceSplitPath;
protected String backgroundPath;
protected boolean enableShader;
protected boolean hideScoreBoardNumber;
protected boolean animatedText;
protected boolean itemsAdderEffect;
protected BossBar.Color removedBarColor;
protected boolean bossBar1_20_2;
protected boolean bossBar1_17;
protected boolean legacyUnicodes;
protected boolean packItemsAdder;
protected boolean packItemsAdderLegacy;
protected boolean packOraxen;
protected boolean packCreativeCentral;
protected boolean chatUnsafe;
protected boolean chatTR;
protected boolean chatVenture;
protected boolean chatHusk;
protected boolean chatCarbon;
protected boolean chatAdvanced;
protected boolean chatEss;
protected String configVersion;
public ConfigManager(CustomNameplates plugin) {
this.plugin = plugin;
instance = this;
}
@Override
public void load() {
configVersion = CustomNameplatesProperties.getValue("config");
MAIN_CONFIG = loadConfig("config.yml",
GeneralSettings.builder()
.setRouteSeparator('.')
.setUseDefaults(false)
.build(),
LoaderSettings
.builder()
.setAutoUpdate(true)
.build(),
DumperSettings.builder()
.setEscapeUnprintable(false)
.setScalarFormatter((tag, value, role, def) -> {
if (role == NodeRole.KEY) {
return ScalarStyle.PLAIN;
} else {
return tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : ScalarStyle.PLAIN;
}
})
.build(),
UpdaterSettings
.builder()
.setVersioning(new BasicVersioning("config-version"))
.addIgnoredRoute(configVersion, "other-settings.placeholder-refresh-interval", '.')
.addIgnoredRoute(configVersion, "other-settings.font-templates", '.')
.addIgnoredRoute(configVersion, "other-settings.shift-fonts", '.')
.build());
try {
MAIN_CONFIG.save(resolveConfig("config.yml").toFile());
} catch (IOException e) {
throw new RuntimeException(e);
}
loadSettings();
}
private void loadSettings() {
YamlDocument config = MAIN_CONFIG;
AdventureHelper.legacySupport = config.getBoolean("other-settings.legacy-color-code-support", true);
TranslationManager.forceLocale(TranslationManager.parseLocale(config.getString("force-locale", "")));
// Basics
debug = config.getBoolean("debug", false);
metrics = config.getBoolean("metrics", false);
checkUpdate = config.getBoolean("update-checker", false);
// Modules
nametagModule = config.getBoolean("modules.nametags", true);
actionbarModule = config.getBoolean("modules.actionbars", true);
imageModule = config.getBoolean("modules.images", true);
bossBarModule = config.getBoolean("modules.bossbars", true);
bubbleModule = config.getBoolean("modules.bubbles", true);
backgroundModule = config.getBoolean("modules.backgrounds", true);
nameplateModule = config.getBoolean("modules.nameplates", true);
// Integrations
packItemsAdder = config.getBoolean("integrations.resource-pack.ItemsAdder", false);
packItemsAdderLegacy = config.getBoolean("integrations.resource-pack.ItemsAdder-old-method", false);
if (packItemsAdder) packItemsAdderLegacy = false;
packOraxen = config.getBoolean("integrations.resource-pack.Oraxen", false);
packCreativeCentral = config.getBoolean("integrations.resource-pack.Creative-Central");
chatUnsafe = config.getBoolean("other-settings.unsafe-chat-event", false);
chatEss = config.getBoolean("integrations.chat.Essentials", false);
chatCarbon = config.getBoolean("integrations.chat.CarbonChat", false);
chatHusk = config.getBoolean("integrations.chat.HuskChat", false);
chatAdvanced = config.getBoolean("integrations.chat.AdvancedChat", false);
chatTR = config.getBoolean("integrations.chat.TrChat", false);
chatVenture = config.getBoolean("integrations.chat.VentureChat", false);
// Packs
generateOnStart = !config.getBoolean("resource-pack.disable-generation-on-start", false);
namespace = config.getString("resource-pack.namespace", "nameplates");
font = config.getString("resource-pack.font", "default");
initialChar = config.getChar("resource-pack.initial-char", '뀁');
CharacterArranger.reset(initialChar);
nameplatePath = config.getString("resource-pack.image-path.nameplates", "font/nameplates/");
backgroundPath = config.getString("resource-pack.image-path.backgrounds", "font/backgrounds/");
imagePath = config.getString("resource-pack.image-path.images", "font/images/");
bubblePath = config.getString("resource-pack.image-path.bubbles", "font/bubbles/");
spaceSplitPath = config.getString("resource-pack.image-path.space-split", "font/base/");
enableShader = config.getBoolean("resource-pack.shader.enable", true);
hideScoreBoardNumber = config.getBoolean("resource-pack.shader.hide-scoreboard-number", false);
animatedText = config.getBoolean("resource-pack.shader.animated-text", false);
itemsAdderEffect = config.getBoolean("resource-pack.shader.ItemsAdder-text-effects", false);
removedBarColor = BossBar.Color.valueOf(config.getString("resource-pack.transparent-bossbar.color", "YELLOW").toUpperCase(Locale.ENGLISH));
bossBar1_20_2 = config.getBoolean("resource-pack.transparent-bossbar.1_20_2+", true);
bossBar1_17 = config.getBoolean("resource-pack.transparent-bossbar.1_17-1_20_1", true);
legacyUnicodes = config.getBoolean("resource-pack.legacy-unicodes", true);
// Other settings
delaySend = config.getInt("other-settings.send-delay", 0);
defaultPlaceholderRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 1);
defaultConditionRefreshInterval = config.getInt("other-settings.ddefault-condition-refresh-interval", 1);
catchOtherActionBar = config.getBoolean("other-settings.catch-other-plugin-actionbar", true);
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);
}
@Override
public void unload() {
Reloadable.super.unload();
}
public static int delaySend() {
return instance.delaySend;
}
public static String spaceSplitPath() {
return instance.spaceSplitPath;
}
public static String bubblePath() {
return instance.bubblePath;
}
public static String imagePath() {
return instance.imagePath;
}
public static String backgroundPath() {
return instance.backgroundPath;
}
public static String nameplatePath() {
return instance.nameplatePath;
}
public static boolean generateOnStart() {
return instance.generateOnStart;
}
public static String namespace() {
return instance.namespace;
}
public static String font() {
return instance.font;
}
public static String configVersion() {
return instance.configVersion;
}
public static char initialChar() {
return instance.initialChar;
}
public static boolean hideTeamNames() {
return instance.hideTeamNames;
}
public static boolean actionbarModule() {
return instance.actionbarModule;
}
public static boolean nametagModule() {
return instance.nametagModule;
}
public static boolean catchOtherActionBar() {
return instance.catchOtherActionBar;
}
public static boolean displaySystemChat() {
return instance.displaySystemChat;
}
public static boolean packItemsAdder() {
return instance.packItemsAdder;
}
public static boolean packItemsAdderLegacy() {
return instance.packItemsAdderLegacy;
}
public static boolean packOraxen() {
return instance.packOraxen;
}
public static boolean packCreativeCentral() { return instance.packCreativeCentral; }
public static boolean hideScoreBoardNumber() {
return instance.hideScoreBoardNumber;
}
public static boolean animatedText() {
return instance.animatedText;
}
public static boolean itemsAdderEffect() {
return instance.itemsAdderEffect;
}
public static BossBar.Color removedBarColor() {
return instance.removedBarColor;
}
public static boolean imageModule() {
return instance.imageModule;
}
public static boolean bossbarModule() {
return instance.bossBarModule;
}
public static boolean bubbleModule() {
return instance.bubbleModule;
}
public static boolean backgroundModule() {
return instance.backgroundModule;
}
public static boolean nameplateModule() {
return instance.nameplateModule;
}
public static boolean debug() {
return instance.debug;
}
public static boolean checkUpdate() {
return instance.checkUpdate;
}
public static boolean metrics() {
return instance.metrics;
}
public static int defaultPlaceholderRefreshInterval() {
return instance.defaultPlaceholderRefreshInterval;
}
public static int defaultConditionRefreshInterval() {
return instance.defaultConditionRefreshInterval;
}
public static int otherActionBarStayTime() {
return instance.otherActionBarStayTime;
}
public static boolean enableShader() {
return instance.enableShader;
}
public static boolean legacyUnicodes() {
return instance.legacyUnicodes;
}
public static boolean bossBar1_20_2() {
return instance.bossBar1_20_2;
}
public static boolean bossBar1_17() {
return instance.bossBar1_17;
}
public static boolean chatUnsafe() {
return instance.chatUnsafe;
}
public static boolean chatTrChat() {
return instance.chatTR;
}
public static boolean chatVenture() {
return instance.chatVenture;
}
public static boolean chatHusk() {
return instance.chatHusk;
}
public static boolean chatEss() {
return instance.chatEss;
}
public static boolean chatCarbon() {
return instance.chatCarbon;
}
public static boolean chatAdvanced() {
return instance.chatAdvanced;
}
@Override
public YamlDocument loadConfig(String filePath) {
return loadConfig(filePath, '.');
}
@Override
public YamlDocument loadConfig(String filePath, char routeSeparator) {
try (InputStream inputStream = new FileInputStream(resolveConfig(filePath).toFile())) {
return YamlDocument.create(
inputStream,
plugin.getResourceStream(filePath),
GeneralSettings.builder().setRouteSeparator(routeSeparator).build(),
LoaderSettings
.builder()
.setAutoUpdate(true)
.build(),
DumperSettings.builder()
.setScalarFormatter((tag, value, role, def) -> {
if (role == NodeRole.KEY) {
return ScalarStyle.PLAIN;
} else {
return tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : ScalarStyle.PLAIN;
}
})
.build(),
UpdaterSettings
.builder()
.setVersioning(new BasicVersioning("config-version"))
.build()
);
} catch (IOException e) {
plugin.getPluginLogger().severe("Failed to load config " + filePath, e);
throw new RuntimeException(e);
}
}
@Override
public YamlDocument loadConfig(String filePath, GeneralSettings generalSettings, LoaderSettings loaderSettings, DumperSettings dumperSettings, UpdaterSettings updaterSettings) {
try (InputStream inputStream = new FileInputStream(resolveConfig(filePath).toFile())) {
return YamlDocument.create(
inputStream,
plugin.getResourceStream(filePath),
generalSettings,
loaderSettings,
dumperSettings,
updaterSettings
);
} catch (IOException e) {
plugin.getPluginLogger().severe("Failed to load config " + filePath, e);
throw new RuntimeException(e);
}
}
@Override
public YamlDocument loadData(File file) {
try (InputStream inputStream = new FileInputStream(file)) {
return YamlDocument.create(inputStream);
} catch (IOException e) {
plugin.getPluginLogger().severe("Failed to load config " + file, e);
throw new RuntimeException(e);
}
}
public Path resolveConfig(String filePath) {
if (filePath == null || filePath.isEmpty()) {
throw new IllegalArgumentException("ResourcePath cannot be null or empty");
}
filePath = filePath.replace('\\', '/');
Path configFile = plugin.getConfigDirectory().resolve(filePath);
// if the config doesn't exist, create it based on the template in the resources dir
if (!Files.exists(configFile)) {
try {
Files.createDirectories(configFile.getParent());
} catch (IOException e) {
// ignore
}
try (InputStream is = plugin.getResourceStream(filePath)) {
if (is == null) {
throw new IllegalArgumentException("The embedded resource '" + filePath + "' cannot be found");
}
Files.copy(is, configFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return configFile;
}
}
@@ -0,0 +1,322 @@
/*
* 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.api;
import net.momirealms.customnameplates.api.feature.actionbar.ActionBarManager;
import net.momirealms.customnameplates.api.feature.advance.AdvanceManager;
import net.momirealms.customnameplates.api.feature.background.BackgroundManager;
import net.momirealms.customnameplates.api.feature.bossbar.BossBarManager;
import net.momirealms.customnameplates.api.feature.bubble.BubbleManager;
import net.momirealms.customnameplates.api.feature.chat.ChatManager;
import net.momirealms.customnameplates.api.feature.image.ImageManager;
import net.momirealms.customnameplates.api.feature.nameplate.NameplateManager;
import net.momirealms.customnameplates.api.feature.pack.ResourcePackManager;
import net.momirealms.customnameplates.api.feature.tag.UnlimitedTagManager;
import net.momirealms.customnameplates.api.network.PacketSender;
import net.momirealms.customnameplates.api.network.PipelineInjector;
import net.momirealms.customnameplates.api.placeholder.PlaceholderManager;
import net.momirealms.customnameplates.api.requirement.RequirementManager;
import net.momirealms.customnameplates.api.storage.StorageManager;
import net.momirealms.customnameplates.common.dependency.DependencyManager;
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 java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Abstract class representing the core plugin management of CustomNameplates.
* Provides access to managers for various features.
*/
public abstract class CustomNameplates implements NameplatesPlugin {
private static CustomNameplates instance;
protected DependencyManager dependencyManager;
protected TranslationManager translationManager;
protected Consumer<Supplier<String>> debugger = (s) -> getPluginLogger().info("[DEBUG] " + s.get());
protected ConfigManager configManager;
protected PacketSender packetSender;
protected PipelineInjector pipelineInjector;
protected PlaceholderManager placeholderManager;
protected RequirementManager requirementManager;
protected ActionBarManager actionBarManager;
protected BossBarManager bossBarManager;
protected UnlimitedTagManager unlimitedTagManager;
protected Platform platform;
protected MainTask mainTask;
protected SchedulerTask scheduledMainTask;
protected ConcurrentHashMap<UUID, CNPlayer> onlinePlayerMap = new ConcurrentHashMap<>();
protected HashMap<Integer, CNPlayer> entityIDFastLookup = new HashMap<>();
protected AdvanceManager advanceManager;
protected BackgroundManager backgroundManager;
protected EventManager eventManager;
protected StorageManager storageManager;
protected BubbleManager bubbleManager;
protected ChatManager chatManager;
protected ImageManager imageManager;
protected NameplateManager nameplateManager;
protected ResourcePackManager resourcePackManager;
protected CustomNameplatesAPI api;
protected CustomNameplates() {
instance = this;
}
/**
* Reloads the plugin
*/
@Override
public abstract void reload();
/**
* Disables the plugin, canceling any scheduled tasks.
*/
@Override
public abstract void disable();
/**
* Logs debug messages through the provided supplier.
*
* @param supplier a supplier that provides debug messages
*/
@Override
public void debug(Supplier<String> supplier) {
this.debugger.accept(supplier);
}
/**
* Returns the dependency manager for managing external dependencies.
*
* @return the {@link DependencyManager} instance
*/
@Override
public DependencyManager getDependencyManager() {
return dependencyManager;
}
/**
* Returns the translation manager for managing language translations.
*
* @return the {@link TranslationManager} instance
*/
@Override
public TranslationManager getTranslationManager() {
return translationManager;
}
/**
* Returns the configuration manager for managing plugin configurations.
*
* @return the {@link ConfigManager} instance
*/
@Override
public ConfigManager getConfigManager() {
return configManager;
}
/**
* Returns the manager responsible for handling placeholders.
*
* @return the {@link PlaceholderManager} instance
*/
public PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
/**
* Returns the packet sender responsible for sending network packets to players.
*
* @return the {@link PacketSender} instance
*/
public PacketSender getPacketSender() {
return packetSender;
}
/**
* Returns the requirement manager responsible for managing requirements.
*
* @return the {@link RequirementManager} instance
*/
public RequirementManager getRequirementManager() {
return requirementManager;
}
/**
* Returns the action bar manager responsible for managing action bar displays.
*
* @return the {@link ActionBarManager} instance
*/
public ActionBarManager getActionBarManager() {
return actionBarManager;
}
/**
* Returns the manager responsible for handling unlimited tags.
*
* @return the {@link UnlimitedTagManager} instance
*/
public UnlimitedTagManager getUnlimitedTagManager() {
return unlimitedTagManager;
}
/**
* Returns the manager responsible for handling font advances.
*
* @return the {@link AdvanceManager} instance
*/
public AdvanceManager getAdvanceManager() {
return advanceManager;
}
/**
* Returns the background manager responsible for handling background images.
*
* @return the {@link BackgroundManager} instance
*/
public BackgroundManager getBackgroundManager() {
return backgroundManager;
}
/**
* Returns the event manager responsible for managing events.
*
* @return the {@link EventManager} instance
*/
@Override
public EventManager getEventManager() {
return eventManager;
}
/**
* Returns the storage manager responsible for handling data storage.
*
* @return the {@link StorageManager} instance
*/
public StorageManager getStorageManager() {
return storageManager;
}
/**
* Returns the nameplate manager responsible for managing nameplate images.
*
* @return the {@link NameplateManager} instance
*/
public NameplateManager getNameplateManager() {
return nameplateManager;
}
/**
* Returns the image manager responsible for handling images used within the plugin.
*
* @return the {@link ImageManager} instance
*/
public ImageManager getImageManager() {
return imageManager;
}
/**
* Returns the bubble manager responsible for managing chat bubbles.
*
* @return the {@link BubbleManager} instance
*/
public BubbleManager getBubbleManager() {
return bubbleManager;
}
/**
* Returns the chat manager responsible for managing chat-related features.
*
* @return the {@link ChatManager} instance
*/
public ChatManager getChatManager() {
return chatManager;
}
/**
* Returns the resource pack manager responsible for managing custom resource packs.
*
* @return the {@link ResourcePackManager} instance
*/
public ResourcePackManager getResourcePackManager() {
return resourcePackManager;
}
/**
* Get the API class
*
* @return api
*/
public CustomNameplatesAPI getAPI() {
return api;
}
/**
* Returns the platform object for accessing platform-specific functionality.
*
* @return the {@link Platform} instance
*/
public Platform getPlatform() {
return platform;
}
/**
* Returns a collection of all currently online players.
*
* @return a collection of {@link CNPlayer} instances
*/
public Collection<CNPlayer> getOnlinePlayers() {
return new HashSet<>(onlinePlayerMap.values());
}
/**
* Retrieves a player by their UUID.
*
* @param uuid the UUID of the player
* @return the {@link CNPlayer} instance, or null if not found
*/
public CNPlayer getPlayer(UUID uuid) {
return onlinePlayerMap.get(uuid);
}
/**
* Retrieves a player by their entity ID.
*
* @param entityID the entity ID of the player
* @return the {@link CNPlayer} instance, or null if not found
*/
public CNPlayer getPlayer(int entityID) {
return entityIDFastLookup.get(entityID);
}
/**
* Returns the singleton instance of CustomNameplates.
*
* @return the {@link CustomNameplates} instance
*/
public static CustomNameplates getInstance() {
return instance;
}
}
@@ -0,0 +1,167 @@
/*
* 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.api;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import net.momirealms.customnameplates.api.feature.background.Background;
import net.momirealms.customnameplates.api.feature.bubble.Bubble;
import net.momirealms.customnameplates.api.feature.nameplate.Nameplate;
import net.momirealms.customnameplates.api.helper.AdventureHelper;
import net.momirealms.customnameplates.api.placeholder.internal.StaticPosition;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.UUID;
public record CustomNameplatesAPI(CustomNameplates plugin) {
private static CustomNameplatesAPI instance;
public CustomNameplatesAPI(CustomNameplates plugin) {
this.plugin = plugin;
instance = this;
}
/**
* Gets the CustomNameplates plugin instance.
*
* @return the CustomNameplates plugin
*/
@Override
public CustomNameplates plugin() {
return plugin;
}
/**
* Retrieves a player by their UUID.
*
* @param uuid the player's UUID
* @return the CNPlayer object if found, otherwise null
*/
@Nullable
public CNPlayer getPlayer(UUID uuid) {
return plugin.getPlayer(uuid);
}
/**
* Retrieves a Background by its ID.
*
* @param id the background ID
* @return an Optional containing the Background if found, or empty if not
*/
@NotNull
public Optional<Background> getBackground(@NotNull String id) {
return Optional.ofNullable(plugin.getBackgroundManager().backgroundById(id));
}
/**
* Retrieves a Nameplate by its ID.
*
* @param id the nameplate ID
* @return an Optional containing the Nameplate if found, or empty if not
*/
@NotNull
public Optional<Nameplate> getNameplate(@NotNull String id) {
return Optional.ofNullable(plugin.getNameplateManager().nameplateById(id));
}
/**
* Retrieves a Bubble by its ID.
*
* @param id the bubble ID
* @return an Optional containing the Bubble if found, or empty if not
*/
@NotNull
public Optional<Bubble> getBubble(@NotNull String id) {
return Optional.ofNullable(plugin.getBubbleManager().bubbleById(id));
}
/**
* Creates a text string with an image, applying margins around the image.
*
* @param text the text to be displayed
* @param adaptiveImage the image to insert with the text
* @param leftMargin the margin to apply on the left of the image
* @param rightMargin the margin to apply on the right of the image
* @return the resulting string with the image and margins
*/
@NotNull
public String createTextWithImage(@NotNull String text, @NotNull AdaptiveImage adaptiveImage, float leftMargin, float rightMargin) {
if (AdventureHelper.legacySupport) {
text = AdventureHelper.legacyToMiniMessage(text);
}
float advance = plugin.getAdvanceManager().getLineAdvance(text);
return adaptiveImage.createImagePrefix(advance, leftMargin, rightMargin) + text + adaptiveImage.createImageSuffix(advance, leftMargin, rightMargin);
}
/**
* Gets the width advance (text length in visual representation) for a given text.
*
* @param text the text to measure
* @return the advance width of the text
*/
public float getTextAdvance(@NotNull String text) {
return plugin.getAdvanceManager().getLineAdvance(text);
}
/**
* Creates a statically positioned text, aligning it to the left, right, or middle
* of the specified width.
*
* @param text the text to be positioned
* @param width the total width for the text positioning
* @param position the desired static position (LEFT, RIGHT, MIDDLE)
* @return the resulting string with the appropriate positioning
*/
@NotNull
public String createStaticText(@NotNull String text, int width, @NotNull StaticPosition position) {
float parsedWidth = CustomNameplates.getInstance().getAdvanceManager().getLineAdvance(text);
switch (position) {
case LEFT -> {
return text + AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth));
}
case RIGHT -> {
return AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)) + text;
}
case MIDDLE -> {
int half = (int) ((width - parsedWidth) / 2);
String left = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(half));
String right = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth - half));
return left + text + right;
}
default -> {
return "";
}
}
}
/**
* Returns the singleton instance of CustomNameplatesAPI.
* Throws an exception if the API has not been initialized.
*
* @return the CustomNameplatesAPI instance
*/
public static CustomNameplatesAPI getInstance() {
if (instance == null) {
throw new RuntimeException("Nameplates API has not been initialized yet.");
}
return instance;
}
}
@@ -1,141 +0,0 @@
/*
* Copyright (C) <2022> <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.api;
import net.momirealms.customnameplates.api.manager.*;
import net.momirealms.customnameplates.api.scheduler.Scheduler;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
public abstract class CustomNameplatesPlugin extends JavaPlugin {
protected static CustomNameplatesPlugin instance;
protected Scheduler scheduler;
protected StorageManager storageManager;
protected VersionManager versionManager;
protected AdventureManager adventureManager;
protected RequirementManager requirementManager;
protected BossBarManager bossBarManager;
protected ImageManager imageManager;
protected PlaceholderManager placeholderManager;
protected ResourcePackManager resourcePackManager;
protected BackGroundManager backGroundManager;
protected TeamManager teamManager;
protected NameplateManager nameplateManager;
protected ActionBarManager actionBarManager;
protected WidthManager widthManager;
protected BubbleManager bubbleManager;
protected CustomNameplatesPlugin() {
instance = this;
}
/* Get plugin instance */
public static CustomNameplatesPlugin getInstance() {
return instance;
}
/* Get plugin instance */
public static CustomNameplatesPlugin get() {
return instance;
}
/* reload the plugin */
public abstract void reload();
/* Get the scheduler */
public Scheduler getScheduler() {
return scheduler;
}
/* Get the storage manager */
public StorageManager getStorageManager() {
return storageManager;
}
/* Get the requirement manager */
public RequirementManager getRequirementManager() {
return requirementManager;
}
/* Get the image manager */
public ImageManager getImageManager() {
return imageManager;
}
/* Get the background manager */
public BackGroundManager getBackGroundManager() {
return backGroundManager;
}
/* Get the resource pack manager */
public ResourcePackManager getResourcePackManager() {
return resourcePackManager;
}
/* Get the adventure manager */
public AdventureManager getAdventure() {
return adventureManager;
}
/* Get the version manager */
public VersionManager getVersionManager() {
return versionManager;
}
/* Get the bossbar manager */
public BossBarManager getBossBarManager() {
return bossBarManager;
}
/* Get the placeholder manager */
public PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
/* Get the team manager */
public TeamManager getTeamManager() {
return teamManager;
}
/* Get the actionbar manager */
public ActionBarManager getActionBarManager() {
return actionBarManager;
}
/* Get the nameplate manager */
public NameplateManager getNameplateManager() {
return nameplateManager;
}
/* Get the width manager */
public WidthManager getWidthManager() {
return widthManager;
}
/* Get the bubble manager */
public BubbleManager getBubbleManager() {
return bubbleManager;
}
/* debug get config by file name */
public abstract YamlConfiguration getConfig(String file);
/* debug message */
public abstract void debug(String s);
}
@@ -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.api;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
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 HashSet<>());
private int timer;
private final CustomNameplates plugin;
public MainTask(CustomNameplates plugin) {
this.plugin = plugin;
}
public static int getTicks() {
return RUN_TICKS;
}
public static boolean hasRequested(int countId) {
return !requestedSharedPlaceholders.add(countId);
}
public static void reset() {
RUN_TICKS = 0;
}
@Override
public void run() {
RUN_TICKS++;
requestedSharedPlaceholders.clear();
long time1 = System.nanoTime();
plugin.actionBarManager.refreshConditions();
plugin.bossBarManager.onTick();
plugin.unlimitedTagManager.onTick();
long time2 = System.nanoTime();
plugin.placeholderManager.refreshPlaceholders();
long time3 = System.nanoTime();
plugin.actionBarManager.checkHeartBeats();
int diff1 = (int) (time2 - time1);
TIME_1.put(timer, diff1);
int diff2 = (int) (time3 - time2);
TIME_2.put(timer, diff2);
timer++;
if (timer >= 1200) timer = 0;
if (RUN_TICKS < 0) {
CustomNameplates.getInstance().reload();
}
}
public static HealthyProfile getHealthyProfile() {
long total1 = TIME_1.values().stream().mapToLong(Integer::longValue).sum();
long total2 = TIME_2.values().stream().mapToLong(Integer::longValue).sum();
long total = total1 + total2;
double size = TIME_1.size();
double load = total / size / 50_000_000;
return new HealthyProfile(
load,
(long) (total / size),
(int) (total1 / size),
(int) (total2 / size)
);
}
public static class HealthyProfile {
private final double load;
private final long totalTimeNS;
private final int actionBarConditionNS;
private final int refreshPlaceholderNS;
public HealthyProfile(
double load,
long totalTimeNS,
int actionBarConditionNS,
int refreshPlaceholderNS
) {
this.actionBarConditionNS = actionBarConditionNS;
this.refreshPlaceholderNS = refreshPlaceholderNS;
this.load = load;
this.totalTimeNS = totalTimeNS;
}
public int getActionBarConditionNS() {
return actionBarConditionNS;
}
public int getRefreshPlaceholderNS() {
return refreshPlaceholderNS;
}
public double getLoad() {
return load;
}
public long getTotalTimeNS() {
return totalTimeNS;
}
}
}
@@ -0,0 +1,236 @@
/*
* 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.api;
import net.momirealms.customnameplates.api.feature.bossbar.BossBar;
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.Vector3;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
/**
* Platform interface to abstract platform-specific operations for Minecraft components, packets, and placeholders.
*/
public interface Platform {
/**
* Converts a JSON string to a Minecraft component.
*
* @param json the JSON string
* @return the Minecraft component object
*/
Object jsonToMinecraftComponent(String json);
/**
* Converts a Minecraft component to a JSON string.
*
* @param component the Minecraft component
* @return the JSON string representation
*/
String minecraftComponentToJson(Object component);
/**
* Creates a vector object from the specified coordinates.
*
* @param x the X coordinate
* @param y the Y coordinate
* @param z the Z coordinate
* @return a vector object
*/
Object vec3(double x, double y, double z);
/**
* Registers a platform-specific placeholder.
*
* @param id the placeholder ID
* @return the registered {@link Placeholder} object
*/
Placeholder registerPlatformPlaceholder(String id);
/**
* Handles an event triggered when a packet is sent to a player.
*
* @param player the player receiving the packet
* @param event the packet event
*/
void onPacketSend(CNPlayer player, PacketEvent event);
/**
* Creates an action bar text packet for displaying a message in the action bar.
*
* @param component the component containing the text
* @return the action bar packet object
*/
Object setActionBarTextPacket(Object component);
/**
* Creates a boss bar packet for displaying a boss bar to a player.
*
* @param uuid the UUID of the boss bar
* @param component the component containing the boss bar text
* @param progress the boss bar progress (0.0 to 1.0)
* @param overlay the boss bar overlay style
* @param color the boss bar color
* @return the boss bar packet object
*/
Object createBossBarPacket(UUID uuid, Object component, float progress, BossBar.Overlay overlay, BossBar.Color color);
/**
* Creates a packet to remove a boss bar.
*
* @param uuid the UUID of the boss bar to remove
* @return the remove boss bar packet object
*/
Object removeBossBarPacket(UUID uuid);
/**
* Creates a packet to update the name of a boss bar.
*
* @param uuid the UUID of the boss bar
* @param component the component containing the new name
* @return the update boss bar name packet object
*/
Object updateBossBarNamePacket(UUID uuid, Object component);
/**
* 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 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
* @return a list of packets for creating the text display
*/
List<Object> createTextDisplayPacket(
int entityID, UUID uuid,
Vector3 position, float pitch, float yaw, double headYaw,
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
);
/**
* Creates a modifier for interpolation delay.
*
* @param delay the interpolation delay
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createInterpolationDelayModifier(int delay);
/**
* Creates a modifier for transformation interpolation duration.
*
* @param duration the transformation interpolation duration
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createTransformationInterpolationDurationModifier(int duration);
/**
* Creates a modifier to change the text component of a packet.
*
* @param component the new text component
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createTextComponentModifier(Object component);
/**
* Creates a modifier to change the scale of a text display.
*
* @param scale the new scale
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createScaleModifier(Vector3 scale);
/**
* Creates a modifier to change the translation of a text display.
*
* @param translation the new translation
* @return a consumer that applies the modifier to a list of packets
*/
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);
/**
* Updates an existing text display entity with modifiers.
*
* @param entityID the entity ID of the text display
* @param modifiers the list of modifiers to apply
* @return the update text display packet object
*/
Object updateTextDisplayPacket(int entityID, List<Consumer<List<Object>>> modifiers);
/**
* Creates a packet to set passengers for a vehicle entity.
*
* @param vehicle the vehicle entity ID
* @param passengers the passenger entity IDs
* @return the set passengers packet object
*/
Object setPassengersPacket(int vehicle, int[] passengers);
/**
* Creates a packet to remove entities from the game world.
*
* @param entityID the entity IDs to remove
* @return the remove entity packet object
*/
Object removeEntityPacket(int... entityID);
/**
* Gets the biome based on location
*
* @param world world
* @param x x
* @param y y
* @param z z
* @return the biome key
*/
String getBiome(String world, int x, int y, int z);
}
@@ -1,58 +0,0 @@
/*
* Copyright (C) <2022> <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.api.data;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface DataStorageInterface {
/**
* Initialize the data resource
*/
void initialize();
/**
* Close the data resource
*/
void disable();
/**
* Get the storage data source type
*
* @return {@link StorageType}
*/
StorageType getStorageType();
/**
* Get a player's data by uuid
* This player can be an offline one
*
* @param uuid uuid
* @return player data
*/
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid);
CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData);
CompletableFuture<Boolean> updateOrInsertPlayerData(UUID uuid, PlayerData playerData);
Set<UUID> getUniqueUsers(boolean legacy);
}
@@ -1,115 +0,0 @@
/*
* Copyright (C) <2022> <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.api.data;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.mechanic.bubble.Bubble;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class OnlineUser {
private final Player player;
private String nameplate;
private String bubble;
public OnlineUser(Player player, PlayerData playerData) {
this.player = player;
this.nameplate = playerData.getNameplate();
this.bubble = playerData.getBubble();
}
public PlayerData toPlayerData() {
return PlayerData.builder()
.setBubble(bubble)
.setNameplate(nameplate)
.build();
}
public UUID getUUID() {
return player.getUniqueId();
}
public Player getPlayer() {
return player;
}
/**
* Get the original nameplate key from data
*/
@NotNull
public String getNameplateKey() {
return nameplate;
}
/**
* Get the original bubble key from data
*/
@NotNull
public String getBubbleKey() {
return bubble;
}
/**
* This value might be inconsistent with the key get by "getNameplateKey()"
* Because if a player doesn't have a nameplate, his nameplate would be the default one
*/
@Nullable
public Nameplate getNameplate() {
String temp = nameplate;
if (temp.equals("none")) {
temp = CustomNameplatesPlugin.get().getNameplateManager().getDefaultNameplate();
}
return CustomNameplatesPlugin.get().getNameplateManager().getNameplate(temp);
}
/**
* This value might be inconsistent with the key get by "getBubbleKey()"
* Because if a player doesn't have a bubble, his bubble would be the default one
*/
@Nullable
public Bubble getBubble() {
String temp = nameplate;
if (temp.equals("none")) {
temp = CustomNameplatesPlugin.get().getBubbleManager().getDefaultBubble();
}
return CustomNameplatesPlugin.get().getBubbleManager().getBubble(temp);
}
/**
* Set nameplate for a player
*
* @param nameplate nameplate
*/
public void setNameplate(String nameplate) {
this.nameplate = nameplate;
}
/**
* Set bubble for a player
*
* @param bubble bubble
*/
public void setBubble(String bubble) {
this.bubble = bubble;
}
}
@@ -1,75 +0,0 @@
/*
* Copyright (C) <2022> <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.api.data;
import com.google.gson.annotations.SerializedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerData {
@SerializedName("nameplate")
private String nameplate;
@SerializedName("bubble")
private String bubble;
public static Builder builder() {
return new Builder();
}
public static PlayerData empty() {
return new PlayerData.Builder()
.setNameplate("none")
.setBubble("none")
.build();
}
public String getNameplate() {
return nameplate;
}
public String getBubble() {
return bubble;
}
public static class Builder {
private final PlayerData playerData;
public Builder() {
this.playerData = new PlayerData();
}
@NotNull
public Builder setNameplate(@Nullable String nameplate) {
this.playerData.nameplate = nameplate;
return this;
}
@NotNull
public Builder setBubble(@Nullable String bubble) {
this.playerData.bubble = bubble;
return this;
}
@NotNull
public PlayerData build() {
return this.playerData;
}
}
}
@@ -1,94 +0,0 @@
/*
* Copyright (C) <2022> <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.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* An event triggered when player sends a message
*/
public class BubblesSpawnEvent extends PlayerEvent implements Cancellable {
private boolean cancelled;
private String bubble;
private String text;
private static final HandlerList handlerList = new HandlerList();
public BubblesSpawnEvent(@NotNull Player who, String bubble, String text) {
super(who, true);
this.cancelled = false;
this.bubble = bubble;
this.text = text;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
/**
* Get the bubble's key
*/
public String getBubble() {
return bubble;
}
/**
* Set the bubble
*
* @param bubble bubble's key
*/
public void setBubble(String bubble) {
this.bubble = bubble;
}
/**
* Get the bubble text content
*/
public String getText() {
return text;
}
/**
* Set the bubble text content
*
* @param text text
*/
public void setText(String text) {
this.text = text;
}
}
@@ -1,50 +0,0 @@
/*
* Copyright (C) <2022> <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.api.event;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Plugin reload event
*/
public class CustomNameplatesReloadEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final CustomNameplatesPlugin plugin;
public CustomNameplatesReloadEvent(CustomNameplatesPlugin plugin) {
this.plugin = plugin;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
public CustomNameplatesPlugin getPlugin() {
return plugin;
}
}
@@ -0,0 +1,37 @@
/*
* 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.api.event;
import net.momirealms.customnameplates.api.storage.data.PlayerData;
import net.momirealms.customnameplates.common.event.NameplatesEvent;
import net.momirealms.customnameplates.common.event.Param;
/**
* Represents an event that is triggered when player data is loaded.
* This event provides access to the {@link PlayerData} for further processing.
*/
public interface DataLoadEvent extends NameplatesEvent {
/**
* Returns the {@link PlayerData} associated with this event.
*
* @return the loaded player data
*/
@Param(0)
PlayerData data();
}
@@ -1,69 +0,0 @@
/*
* Copyright (C) <2022> <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.api.event;
import net.momirealms.customnameplates.api.data.OnlineUser;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Player data loaded event
*/
public class NameplateDataLoadEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final UUID uuid;
private final OnlineUser onlineUser;
public NameplateDataLoadEvent(UUID uuid, OnlineUser onlineUser) {
super(true);
this.uuid = uuid;
this.onlineUser = onlineUser;
}
/**
* Get the UUID
*
* @return uuid
*/
public UUID getUUID() {
return uuid;
}
/**
* Get the online user
*
* @return online user
*/
public OnlineUser getOnlineUser() {
return onlineUser;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}
@@ -0,0 +1,26 @@
/*
* 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.api.event;
import net.momirealms.customnameplates.common.event.NameplatesEvent;
/**
* Represents an event that is triggered when the nameplates configuration is reloaded.
*/
public interface NameplatesReloadEvent extends NameplatesEvent {
}
@@ -0,0 +1,51 @@
/*
* 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.api.feature;
public interface AdaptiveImage {
/**
* Creates the prefix for the image with the specified advance and margins.
*
* @param advance the advance for the image
* @param leftMargin the left margin for the image
* @param rightMargin the right margin for the image
* @return the generated image prefix
*/
String createImagePrefix(float advance, float leftMargin, float rightMargin);
/**
* Creates the suffix for the image with the specified advance and margins.
*
* @param advance the advance for the image
* @param leftMargin the left margin for the image
* @param rightMargin the right margin for the image
* @return the generated image suffix
*/
String createImageSuffix(float advance, float leftMargin, float rightMargin);
/**
* Creates the full image string with the specified advance and margins.
*
* @param advance the advance for the image
* @param leftMargin the left margin for the image
* @param rightMargin the right margin for the image
* @return the generated image string
*/
String createImage(float advance, float leftMargin, float rightMargin);
}
@@ -0,0 +1,94 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.requirement.Requirement;
/**
* Represents a piece of carousel text, which cycles through a series of texts with associated requirements and duration.
*/
public class CarouselText {
private final int duration;
private final Requirement[] requirements;
private final String rawText;
private final PreParsedDynamicText preParsedDynamicText;
private final boolean updateOnDisplay;
/**
* Constructs a new CarouselText instance.
*
* @param duration the duration (in ticks) for how long this text is displayed
* @param requirements the requirements for displaying this text
* @param rawText the raw text content
* @param updateOnDisplay whether the text should be updated when displayed
*/
public CarouselText(int duration, Requirement[] requirements, String rawText, boolean updateOnDisplay) {
this.duration = duration;
this.requirements = requirements;
this.rawText = rawText;
this.preParsedDynamicText = new PreParsedDynamicText(rawText);
this.preParsedDynamicText.init();
this.updateOnDisplay = updateOnDisplay;
}
/**
* Returns the duration (in ticks) for how long this text will be displayed.
*
* @return the display duration
*/
public int duration() {
return duration;
}
/**
* Returns the requirements that must be met to display this text.
*
* @return an array of requirements
*/
public Requirement[] requirements() {
return requirements;
}
/**
* Returns the raw text content.
*
* @return the raw text
*/
public String text() {
return rawText;
}
/**
* Returns the pre-parsed dynamic text, which processes placeholders or dynamic content.
*
* @return the pre-parsed dynamic text
*/
public PreParsedDynamicText preParsedDynamicText() {
return preParsedDynamicText;
}
/**
* Checks if the text should be updated each time it is displayed.
*
* @return true if the text updates on display, false otherwise
*/
public boolean updateOnDisplay() {
return updateOnDisplay;
}
}
@@ -15,20 +15,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.character;
package net.momirealms.customnameplates.api.feature;
/**
* Utility class for automatically arranging characters.
* Provides methods to increase, retrieve, and reset the current character.
*/
public class CharacterArranger {
/**
* The current character being managed by the arranger.
*/
public static char currentChar;
/**
* Increases the current character by 1.
*/
public static void increase() {
currentChar = (char) (currentChar + '\u0001');
}
/**
* Get and increase the char arranged automatically by the plugin
* Retrieves the current character and then increases it.
*
* @return char
* @return the current character before increase
*/
public static char getAndIncrease() {
char temp = currentChar;
@@ -37,9 +47,9 @@ public class CharacterArranger {
}
/**
* Increase and get the char arranged automatically by the plugin
* Increases the current character and then retrieves it.
*
* @return char
* @return the current character after increase
*/
public static char increaseAndGet() {
increase();
@@ -47,11 +57,11 @@ public class CharacterArranger {
}
/**
* Reset the initial char
* Resets the current character to the specified value.
*
* @param c char
* @param c the character to reset to
*/
public static void reset(char c) {
currentChar = c;
}
}
}
@@ -0,0 +1,36 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Represents a listener for player chat events, providing a callback method
* when a player sends a message in a specific channel.
*/
public interface ChatListener {
/**
* Called when a player sends a chat message in a specified channel.
*
* @param player the player who sent the message
* @param message the content of the message
* @param channel the channel where the message was sent
*/
void onPlayerChat(CNPlayer player, String message, String channel);
}
@@ -0,0 +1,166 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CustomNameplates;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
* Represents a configured character with associated image, dimensions, and advance (spacing).
*/
public class ConfiguredCharacter {
private final char character;
private final File imageFile;
private final int height;
private final int ascent;
private final float advance;
/**
* Creates a new ConfiguredCharacter instance using an automatically assigned character.
*
* @param imageFile the image file associated with this character
* @param ascent the ascent value (distance from the baseline to the top of the character)
* @param height the height of the character
* @return a new ConfiguredCharacter instance
*/
public static ConfiguredCharacter create(File imageFile, int ascent, int height) {
return new ConfiguredCharacter(CharacterArranger.getAndIncrease(), imageFile, ascent, height);
}
/**
* Creates a new ConfiguredCharacter instance using an automatically assigned character and a specified advance value.
*
* @param imageFile the image file associated with this character
* @param ascent the ascent value (distance from the baseline to the top of the character)
* @param height the height of the character
* @param advance the advance (spacing) for this character
* @return a new ConfiguredCharacter instance
*/
public static ConfiguredCharacter create(File imageFile, int ascent, int height, float advance) {
return new ConfiguredCharacter(CharacterArranger.getAndIncrease(), imageFile, ascent, height, advance);
}
/**
* Constructs a new ConfiguredCharacter instance with specified character, image, ascent, height, and advance values.
*
* @param character the character to associate
* @param imageFile the image file
* @param ascent the ascent value
* @param height the height of the character
* @param advance the advance (spacing) for the character
*/
public ConfiguredCharacter(char character, File imageFile, int ascent, int height, float advance) {
this.character = character;
this.imageFile = imageFile;
this.ascent = ascent;
this.height = height;
this.advance = advance;
}
/**
* Constructs a new ConfiguredCharacter instance with automatic advance calculation.
*
* @param character the character to associate
* @param imageFile the image file
* @param ascent the ascent value
* @param height the height of the character
*/
public ConfiguredCharacter(char character, File imageFile, int ascent, int height) {
this.character = character;
this.imageFile = imageFile;
this.ascent = ascent;
this.height = height;
if (this.ascent > this.height) {
CustomNameplates.getInstance().getPluginLogger().severe(String.format(
"Found an issue in the image config. Ascent(%s) is higher than height(%s). %s", ascent, height, imageFile.getAbsolutePath()));
}
try {
BufferedImage bufferedImage = ImageIO.read(imageFile);
int imageHeight = bufferedImage.getHeight();
int imageWidth = bufferedImage.getWidth();
float scale = (float) height / imageHeight;
int i;
outer:
for (i = imageWidth - 1; i >= 0; --i) {
for (int k = 0; k < imageHeight; ++k) {
int rgb = bufferedImage.getRGB(i, k);
int alpha = (rgb >> 24) & 0xff;
if (alpha != 0) {
break outer;
}
}
}
advance = (float) Math.round((i + 1) * scale) + 1f;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Returns the character associated with this ConfiguredCharacter.
*
* @return the character
*/
public char character() {
return character;
}
/**
* Returns the ascent value of this character.
*
* @return the ascent value
*/
public int ascent() {
return ascent;
}
/**
* Returns the advance (spacing) of this character.
*
* @return the advance value
*/
public float advance() {
return advance;
}
/**
* Returns the height of this character.
*
* @return the character height
*/
public int height() {
return height;
}
/**
* Returns the image file associated with this character.
*
* @return the image file
*/
public File imageFile() {
return imageFile;
}
}
@@ -0,0 +1,80 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
/**
* Represents dynamic text that can be rendered for a specific player, with support for placeholders and custom text functions.
*/
public class DynamicText {
private final String text;
private final List<Function<CNPlayer, String>> texts;
private final Set<Placeholder> placeholders;
/**
* Constructs a new DynamicText instance.
*
* @param text the raw text string
* @param texts a list of functions that generate text dynamically based on the player
* @param placeholders a set of placeholders used in the text
*/
public DynamicText(String text, List<Function<CNPlayer, String>> texts, Set<Placeholder> placeholders) {
this.text = text;
this.texts = texts;
this.placeholders = placeholders;
}
/**
* Returns the set of placeholders associated with this dynamic text.
*
* @return a set of placeholders
*/
public Set<Placeholder> placeholders() {
return placeholders;
}
/**
* Renders the dynamic text for the specified player by applying the text functions.
*
* @param viewer the player for whom the text is being rendered
* @return the rendered text
*/
public String render(CNPlayer viewer) {
StringBuilder builder = new StringBuilder();
for (Function<CNPlayer, String> function : texts) {
builder.append(function.apply(viewer));
}
return builder.toString();
}
/**
* Returns the raw text string.
*
* @return the raw text
*/
public String text() {
return text;
}
}
@@ -0,0 +1,58 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import java.util.Set;
/**
* Represents a feature that can utilize placeholders and manage updates based on player interaction.
*/
public interface Feature {
/**
* Returns the name of the feature.
*
* @return the feature name
*/
String name();
/**
* Returns the set of placeholders that are currently active within this feature.
*
* @return a set of active placeholders
*/
Set<Placeholder> activePlaceholders();
/**
* Returns the set of all placeholders that this feature can use.
*
* @return a set of all possible placeholders
*/
Set<Placeholder> allPlaceholders();
/**
* Notifies the feature that placeholders for the specified player have been updated.
*
* @param p1 the player whose placeholders have been updated
* @param force if true, forces an update even if no changes are detected
*/
void notifyPlaceholderUpdates(CNPlayer p1, boolean force);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* 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
@@ -15,20 +15,26 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
package net.momirealms.customnameplates.api.feature;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import net.momirealms.customnameplates.api.CNPlayer;
public interface ActionBarManager {
/**
* Listener for handling player join and quit events.
*/
public interface JoinQuitListener {
/**
* Get the actionbar sent by other plugins in MiniMessage format
* Return "" if no other actionbar received
* Called when a player joins the server.
*
* @param player receiver
* @return text
* @param player the player who joined
*/
@NotNull
String getOtherPluginActionBar(Player player);
void onPlayerJoin(CNPlayer player);
/**
* Called when a player quits the server.
*
* @param player the player who quit
*/
void onPlayerQuit(CNPlayer player);
}
@@ -0,0 +1,183 @@
/*
* Copyright (C) <2022> <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.api.feature;
import java.util.HashMap;
public enum OffsetFont {
NEG_1('\uf800', -1, -3),
NEG_2('\uf801', -2, -4),
NEG_3('\uf802', -3, -5),
NEG_4('\uf803', -4, -6),
NEG_5('\uf804', -5, -7),
NEG_6('\uf805', -6, -8),
NEG_7('\uf806', -7, -9),
NEG_8('\uf807', -8, -10),
NEG_9('\uf808', -9, -11),
NEG_10('\uf809', -10, -12),
NEG_11('\uf80a', -11, -13),
NEG_12('\uf80b', -12, -14),
NEG_13('\uf80c', -13, -15),
NEG_14('\uf80d', -14, -16),
NEG_15('\uf80e', -15, -17),
NEG_16('\uf80f', -16, -18),
NEG_24('\uf810', -24, -26),
NEG_32('\uf811', -32, -34),
NEG_48('\uf812', -48, -50),
NEG_64('\uf813', -64, -66),
NEG_128('\uf814', -128, -130),
NEG_256('\uf815', -256, -258),
POS_1('\uf830', 1, -1),
POS_2('\uf831', 2, 1),
POS_3('\uf832', 3, 2),
POS_4('\uf833', 4, 3),
POS_5('\uf834', 5, 4),
POS_6('\uf835', 6, 5),
POS_7('\uf836', 7, 6),
POS_8('\uf837', 8, 7),
POS_9('\uf838', 9, 8),
POS_10('\uf839', 10, 9),
POS_11('\uf83a', 11, 10),
POS_12('\uf83b', 12, 11),
POS_13('\uf83c', 13, 12),
POS_14('\uf83d', 14, 13),
POS_15('\uf83e', 15, 14),
POS_16('\uf83f', 16, 15),
POS_24('\uf840', 24, 23),
POS_32('\uf841', 32, 31),
POS_48('\uf842', 48, 47),
POS_64('\uf843', 64, 63),
POS_128('\uf844', 128, 127),
POS_256('\uf845', 256, 255);
private static final HashMap<Integer, OffsetFont> negFastLookup = new HashMap<>();
private static final HashMap<Integer, OffsetFont> posFastLookup = new HashMap<>();
static {
for (OffsetFont f : OffsetFont.values()) {
if (f.advance > 0) {
posFastLookup.put(f.advance, f);
} else {
negFastLookup.put(-f.advance, f);
}
}
}
private final char character;
private final int advance;
private final int height;
OffsetFont(char character, int advance, int height) {
this.character = character;
this.advance = advance;
this.height = height;
}
public char character() {
return this.character;
}
public float advance() {
return this.advance;
}
public int height() {
return this.height;
}
public static String createOffsets(float offset) {
if (offset >= 0) {
return shortestPosChars(offset);
} else {
return shortestNegChars(-offset);
}
}
public static String shortestNegChars(float advance) {
int n = (int) Math.ceil(advance);
StringBuilder stringBuilder = new StringBuilder();
while (n >= 256) {
stringBuilder.append(OffsetFont.NEG_256.character());
n -= 256;
}
if (n - 128 >= 0) {
stringBuilder.append(OffsetFont.NEG_128.character());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_64.character());
n -= 64;
}
if (n - 48 >= 0) {
stringBuilder.append(OffsetFont.NEG_48.character());
n -= 48;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_32.character());
n -= 32;
}
if (n - 24 >= 0) {
stringBuilder.append(OffsetFont.NEG_24.character());
n -= 24;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_16.character());
n -= 16;
}
if (n == 0) return stringBuilder.toString();
stringBuilder.append(negFastLookup.get(n).character());
return stringBuilder.toString();
}
public static String shortestPosChars(float advance) {
int n = (int) Math.ceil(advance);
StringBuilder stringBuilder = new StringBuilder();
while (n >= 256) {
stringBuilder.append(OffsetFont.POS_256.character());
n -= 256;
}
if (n - 128 >= 0) {
stringBuilder.append(OffsetFont.POS_128.character());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.POS_64.character());
n -= 64;
}
if (n - 48 >= 0) {
stringBuilder.append(OffsetFont.POS_48.character());
n -= 48;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.POS_32.character());
n -= 32;
}
if (n - 24 >= 0) {
stringBuilder.append(OffsetFont.POS_24.character());
n -= 24;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.POS_16.character());
n -= 16;
}
if (n == 0) return stringBuilder.toString();
stringBuilder.append(posFastLookup.get(n).character());
return stringBuilder.toString();
}
}
@@ -0,0 +1,47 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Listener for handling player actions
*/
public interface PlayerListener {
/**
* Called when a player changes the world
*
* @param player the player who changes the world
*/
void onChangeWorld(CNPlayer player);
/**
* Called when a player respawns
*
* @param player the player who respawns
*/
void onRespawn(CNPlayer player);
/**
* Called when a player teleports
*
* @param player the player who respawns
*/
void onTeleport(CNPlayer player);
}
@@ -0,0 +1,117 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.CustomNameplates;
import net.momirealms.customnameplates.api.placeholder.*;
import java.util.*;
import java.util.function.Function;
public class PreParsedDynamicText {
private final String text;
private final List<Function<CNPlayer, Function<CNPlayer, String>>> textFunctions = new ArrayList<>();
private final Set<Placeholder> set = new HashSet<>();
private boolean init = false;
public PreParsedDynamicText(String text) {
this.text = Objects.requireNonNull(text);
}
public PreParsedDynamicText(String text, boolean init) {
this.text = Objects.requireNonNull(text);
if (init) init();
}
public void init() {
if (init) return;
init = true;
PlaceholderManager manager = CustomNameplates.getInstance().getPlaceholderManager();
List<String> detectedPlaceholders = manager.detectPlaceholders(text);
List<Function<CNPlayer, Function<CNPlayer, String>>> convertor = new ArrayList<>(detectedPlaceholders.size());
List<Placeholder> placeholders = new ArrayList<>(detectedPlaceholders.size());
for (String id : detectedPlaceholders) {
Placeholder placeholder = manager.getPlaceholder(id);
placeholders.add(placeholder);
if (placeholder instanceof RelationalPlaceholder) {
convertor.add((owner) -> (viewer) -> owner.getRelationalData(placeholder, viewer));
} else if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
convertor.add((owner) -> (viewer) -> {
if (owner != null) {
return owner.getData(placeholder);
} else {
return playerPlaceholder.request(null);
}
});
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
convertor.add((owner) -> (viewer) -> sharedPlaceholder.getLatestValue());
} else {
convertor.add((owner) -> (viewer) -> id);
}
}
int placeholderSize = placeholders.size();
StringBuilder original0 = new StringBuilder(text);
int lastIndex = 0;
for (int i = 0; i < placeholderSize; i++) {
String id = placeholders.get(i).id();
int index = original0.indexOf(id, lastIndex);
if (index == -1) {
throw new RuntimeException("Placeholder ID not found in text");
}
if (index != lastIndex) {
String textBefore = original0.substring(lastIndex, index);
textFunctions.add((owner) -> (viewer) -> textBefore);
}
textFunctions.add(convertor.get(i));
lastIndex = index + id.length();
}
if (lastIndex < original0.length()) {
String remaining = original0.substring(lastIndex);
textFunctions.add((owner) -> (viewer) -> remaining);
}
// To optimize the tree height, call new HashSet twice here
set.addAll(new HashSet<>(placeholders));
}
public DynamicText fastCreate(CNPlayer player) {
List<Function<CNPlayer, String>> functions = new ArrayList<>();
for (Function<CNPlayer, Function<CNPlayer, String>> textFunction : textFunctions) {
functions.add(textFunction.apply(player));
}
return new DynamicText(text, functions, set);
}
public Set<Placeholder> placeholders() {
return set;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
PreParsedDynamicText that = (PreParsedDynamicText) object;
return text.equals(that.text);
}
@Override
public int hashCode() {
return text.hashCode();
}
}
@@ -0,0 +1,35 @@
/*
* 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.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Represents a feature that involves relationships between two players and supports placeholder updates for both players.
*/
public interface RelationalFeature extends Feature {
/**
* Notifies the feature that placeholders for the relationship between two players have been updated.
*
* @param p1 the first player
* @param p2 the second player
* @param force if true, forces an update even if no changes are detected
*/
void notifyPlaceholderUpdates(CNPlayer p1, CNPlayer p2, boolean force);
}
@@ -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.api.feature;
import net.momirealms.customnameplates.api.MainTask;
/**
* Represents a data structure that stores an object and tracks when it was last updated,
* using packed ticks and a boolean flag to indicate changes.
*
* @param <D> the type of data being stored
*/
public class TimeStampData<D> {
private D data;
private int packedTicks;
/**
* Constructs a new TickStampData instance.
*
* @param data the data to store
* @param ticks the number of ticks to store
* @param changed whether the value has changed
*/
public TimeStampData(D data, int ticks, boolean changed) {
this.data = data;
this.packedTicks = packBooleanAndTicks(changed, ticks);
}
/**
* Updates the stored data.
*
* @param data the new data
*/
public void data(D data) {
this.data = data;
}
/**
* Updates the packed ticks and change status.
*
* @param changed whether the value has changed
*/
public void updateTicks(boolean changed) {
this.packedTicks = packBooleanAndTicks(changed, MainTask.getTicks());
}
/**
* Consume the flag
*/
public void resetChangedFlag() {
this.packedTicks = packedTicks & 0x7FFFFFFF;;
}
/**
* Returns the stored data.
*
* @return the data
*/
public D data() {
return data;
}
/**
* Checks if the value has changed since the last update.
*
* @return true if the value has changed, false otherwise
*/
public boolean hasValueChanged() {
return unpackBoolean(packedTicks);
}
/**
* Returns the stored number of ticks.
*
* @return the number of ticks
*/
public int ticks() {
return unpackTicks(packedTicks);
}
/**
* Packs the boolean change flag and ticks into a single integer.
*
* @param hasValueChanged whether the value has changed
* @param ticks the number of ticks
* @return the packed integer
*/
public static int packBooleanAndTicks(boolean hasValueChanged, int ticks) {
int numberMasked = ticks & 0x7FFFFFFF; // Mask for 31 bits
int booleanBit = hasValueChanged ? 1 << 31 : 0; // Set the highest bit for the boolean flag
return booleanBit | numberMasked;
}
/**
* Unpacks the number of ticks from the packed integer.
*
* @param packed the packed integer
* @return the number of ticks
*/
public static int unpackTicks(int packed) {
return packed & 0x7FFFFFFF; // Extract the lower 31 bits for ticks
}
/**
* Unpacks the boolean change flag from the packed integer.
*
* @param packed the packed integer
* @return true if the value has changed, false otherwise
*/
public static boolean unpackBoolean(int packed) {
return (packed & 0x80000000) != 0; // Check the highest bit for the boolean flag
}
}
@@ -0,0 +1,91 @@
/*
* 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.api.feature.actionbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
public interface ActionBarConfig {
/**
* Returns the unique ID of the ActionBar configuration.
*
* @return the configuration ID
*/
String id();
/**
* Returns the list of requirements for the ActionBar.
*
* @return an array of requirements
*/
Requirement[] requirements();
/**
* Returns the carousel texts used in the ActionBar.
*
* @return an array of carousel texts
*/
CarouselText[] carouselTexts();
/**
* Creates a new builder for constructing an ActionBarConfig.
*
* @return a new builder instance
*/
static Builder builder() {
return new ActionBarConfigImpl.BuilderImpl();
}
/**
* Builder for creating an ActionBarConfig.
*/
interface Builder {
/**
* Sets the unique ID for the ActionBar configuration.
*
* @param id the configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the requirements for the ActionBar.
*
* @param requirements an array of requirements
* @return the builder instance
*/
Builder requirement(Requirement[] requirements);
/**
* Sets the carousel texts for the ActionBar.
*
* @param carouselTexts an array of carousel texts
* @return the builder instance
*/
Builder carouselText(CarouselText[] carouselTexts);
/**
* Builds and returns the ActionBarConfig.
*
* @return the constructed ActionBarConfig
*/
ActionBarConfig build();
}
}
@@ -0,0 +1,81 @@
/*
* 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.api.feature.actionbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import static java.util.Objects.requireNonNull;
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) {
this.id = requireNonNull(id);
this.requirements = requireNonNull(requirements);
this.carouselTexts = requireNonNull(carouselTexts);
}
@Override
public String id() {
return id;
}
@Override
public Requirement[] requirements() {
return requirements;
}
@Override
public CarouselText[] carouselTexts() {
return carouselTexts;
}
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] requirements;
private CarouselText[] carouselTexts;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder requirement(Requirement[] requirements) {
this.requirements = requirements;
return this;
}
@Override
public Builder carouselText(CarouselText[] carouselTexts) {
this.carouselTexts = carouselTexts;
return this;
}
@Override
public ActionBarConfig build() {
return new ActionBarConfigImpl(id, requirements, carouselTexts);
}
}
}
@@ -0,0 +1,60 @@
/*
* 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.api.feature.actionbar;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
public interface ActionBarManager extends Reloadable {
/**
* Refreshes the conditions of all ActionBars.
*/
void refreshConditions();
/**
* Checks heartbeats for any necessary updates or actions related to ActionBars.
*/
void checkHeartBeats();
/**
* Retrieves the ActionBar configuration by its name.
*
* @param name the name of the ActionBar configuration
* @return the corresponding ActionBarConfig, or null if not found
*/
@Nullable
ActionBarConfig configById(String name);
/**
* Returns all available ActionBar configurations.
*
* @return an array of all ActionBarConfig instances
*/
ActionBarConfig[] actionBarConfigs();
/**
* Gets the external ActionBar for a specific player.
*
* @param player the player
* @return the external ActionBar string for the player
*/
@Nullable
String getExternalActionBar(CNPlayer player);
}
@@ -0,0 +1,84 @@
/*
* 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.api.feature.advance;
import net.kyori.adventure.key.Key;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import net.momirealms.customnameplates.common.util.Tuple;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface AdvanceManager extends Reloadable {
/**
* Retrieves custom font advance data by its ID.
*
* @param id the ID of the custom font
* @return the custom font advance data
*/
@Nullable
ConfigurableFontAdvanceData customFontDataById(String id);
/**
* Retrieves character font advance data by its ID.
*
* @param id the ID of the character font
* @return the character font advance data
*/
@Nullable
CharacterFontAdvanceData templateFontDataById(String id);
/**
* Calculates the total advance (width) for a line of text.
*
* @param text the text to calculate the advance for
* @return the total line advance
*/
float getLineAdvance(String text);
/**
* Calculates the advance (width) for a series of characters with a specific font and style.
*
* @param chars the array of characters
* @param font the font key
* @param bold whether the text is bold
* @return the total character advance
*/
float getCharAdvance(char[] chars, Key font, boolean bold);
/**
* Calculates the number of lines needed to fit the text within a specified width.
*
* @param text the text to calculate the number of lines for
* @param width the maximum width of each line
* @return the number of lines required
*/
int getLines(String text, int width);
/**
* Converts a MiniMessage-formatted string into an iterable list of tuples.
* Each tuple contains text, its corresponding font key, and whether it is bold.
*
* @param text the MiniMessage-formatted string
* @return a list of tuples representing the iterable text parts
*/
@ApiStatus.Internal
List<Tuple<String, Key, Boolean>> miniMessageToIterable(String text);
}
@@ -0,0 +1,110 @@
/*
* 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.api.feature.advance;
import com.google.gson.JsonObject;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public interface CharacterFontAdvanceData {
/**
* Returns the size of the character font advance data, typically the number of characters.
*
* @return the size of the data
*/
int size();
/**
* Retrieves the advance (width) for a specific character code point.
*
* @param codePoint the code point of the character
* @return the advance value for the character, or null if not found
*/
Float getAdvance(int codePoint);
/**
* Returns the map containing the character code points and their corresponding advance values.
*
* @return a map of character code points and their advances
*/
Map<Integer, Float> data();
/**
* Returns the unique identifier for this font advance data.
*
* @return the font advance data ID
*/
String id();
/**
* Generates a list of font provider configurations based on the provided properties.
*
* @param properties a map of properties for font provider configuration
* @return a list of JSON objects representing the font providers
*/
List<JsonObject> fontProvider(Map<String, Object> properties);
/**
* Creates a new builder for constructing CharacterFontAdvanceData.
*
* @return a new builder instance
*/
static Builder builder() {
return new CharacterFontAdvanceDataImpl.BuilderImpl();
}
/**
* Builder for creating CharacterFontAdvanceData.
*/
interface Builder {
/**
* Sets the advance data for the characters.
*
* @param data a map of character code points and their advance values
* @return the builder instance
*/
Builder advance(Map<Integer, Float> data);
/**
* Sets the unique ID for the font advance data.
*
* @param id the ID of the font advance data
* @return the builder instance
*/
Builder id(String id);
/**
* Sets a function to provide the font provider configuration.
*
* @param function a function that takes properties and returns a list of JSON objects representing font providers
* @return the builder instance
*/
Builder fontProviderFunction(Function<Map<String, Object>, List<JsonObject>> function);
/**
* Builds and returns the CharacterFontAdvanceData instance.
*
* @return the constructed CharacterFontAdvanceData
*/
CharacterFontAdvanceData build();
}
}
@@ -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.api.feature.advance;
import com.google.gson.JsonObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static java.util.Objects.requireNonNull;
public class CharacterFontAdvanceDataImpl implements CharacterFontAdvanceData {
private final HashMap<Integer, Float> data;
private final String id;
private final Function<Map<String, Object>, List<JsonObject>> fontProviderFunction;
public CharacterFontAdvanceDataImpl(String id, HashMap<Integer, Float> data, Function<Map<String, Object>, List<JsonObject>> fontProviderFunction) {
this.data = data;
this.id = requireNonNull(id);
this.fontProviderFunction = requireNonNull(fontProviderFunction);
}
@Override
public int size() {
return data.size();
}
@Override
public Float getAdvance(int codePoint) {
return data.get(codePoint);
}
@Override
public Map<Integer, Float> data() {
return data;
}
@Override
public String id() {
return id;
}
@Override
public List<JsonObject> fontProvider(Map<String, Object> properties) {
return fontProviderFunction.apply(properties);
}
public static class BuilderImpl implements Builder {
private final HashMap<Integer, Float> data = new HashMap<>();
private String id;
private Function<Map<String, Object>, List<JsonObject>> fontProviderFunction = (stringObjectMap -> null);
@Override
public Builder advance(Map<Integer, Float> data) {
this.data.putAll(data);
return this;
}
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder fontProviderFunction(Function<Map<String, Object>, List<JsonObject>> function) {
this.fontProviderFunction = function;
return this;
}
@Override
public CharacterFontAdvanceData build() {
return new CharacterFontAdvanceDataImpl(id, data, fontProviderFunction);
}
}
}
@@ -0,0 +1,103 @@
/*
* 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.api.feature.advance;
import java.util.List;
/**
* Represents configurable font advance data, including default advance values and per-character advances.
*/
public interface ConfigurableFontAdvanceData {
/**
* Returns the default advance (width) used when no specific value is defined for a character.
*
* @return the default advance width
*/
float defaultAdvance();
/**
* Retrieves the advance (width) for a specific character code point.
*
* @param codePoint the code point of the character
* @return the advance value for the character, or the default advance if not defined
*/
float getAdvance(int codePoint);
/**
* Returns the unique identifier for this configurable font advance data.
*
* @return the font advance data ID
*/
String id();
/**
* Creates a new builder for constructing ConfigurableFontAdvanceData.
*
* @return a new builder instance
*/
static Builder builder() {
return new ConfigurableFontAdvanceDataImpl.BuilderImpl();
}
/**
* Builder for creating ConfigurableFontAdvanceData.
*/
interface Builder {
/**
* Sets the unique ID for the configurable font advance data.
*
* @param id the ID of the font advance data
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the default advance (width) for characters that do not have specific advances.
*
* @param width the default advance width
* @return the builder instance
*/
Builder defaultAdvance(float width);
/**
* Sets the advance (width) for a specific character code point.
*
* @param codePoint the code point of the character
* @param width the advance width for the character
* @return the builder instance
*/
Builder advance(int codePoint, float width);
/**
* Sets the parent fonts used by this configurable font advance data.
*
* @param font a list of parent fonts
* @return the builder instance
*/
Builder parentFont(List<CharacterFontAdvanceData> font);
/**
* Builds and returns the ConfigurableFontAdvanceData instance.
*
* @return the constructed ConfigurableFontAdvanceData
*/
ConfigurableFontAdvanceData build();
}
}
@@ -0,0 +1,110 @@
/*
* 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.api.feature.advance;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import static java.util.Objects.requireNonNull;
public class ConfigurableFontAdvanceDataImpl implements ConfigurableFontAdvanceData {
private final float defaultAdvance;
private final HashMap<Integer, Float> data = new HashMap<>();
private final List<CharacterFontAdvanceData> parents = new ArrayList<>();
private final String id;
public ConfigurableFontAdvanceDataImpl(String id, float defaultAdvance, HashMap<Integer, Float> customData, List<CharacterFontAdvanceData> parentFonts) {
this.id = requireNonNull(id);
this.defaultAdvance = defaultAdvance;
for (CharacterFontAdvanceData parent : parentFonts) {
// To optimize memory, especially for those fonts that have over 100,000 characters
if (parent.size() > 2048) {
parents.add(parent);
} else {
data.putAll(parent.data());
}
}
data.putAll(customData);
Collections.reverse(parents);
}
@Override
public float defaultAdvance() {
return defaultAdvance;
}
@Override
public float getAdvance(int codePoint) {
Float width = data.get(codePoint);
if (width == null) {
for (CharacterFontAdvanceData parent : parents) {
width = parent.getAdvance(codePoint);
if (width != null) {
return width;
}
}
return defaultAdvance;
}
return width;
}
@Override
public String id() {
return id;
}
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;
private String id;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder defaultAdvance(float width) {
this.defaultAdvance = width;
return this;
}
@Override
public Builder advance(int codePoint, float width) {
this.customData.put(codePoint, width);
return this;
}
@Override
public Builder parentFont(List<CharacterFontAdvanceData> font) {
this.parents.addAll(font);
return this;
}
@Override
public ConfigurableFontAdvanceData build() {
return new ConfigurableFontAdvanceDataImpl(id, defaultAdvance, customData, parents);
}
}
}
@@ -0,0 +1,214 @@
/*
* 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.api.feature.background;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
/**
* Represents a background configuration
*/
public interface Background extends AdaptiveImage {
/**
* Returns the unique ID of the background configuration.
*
* @return the background ID
*/
String id();
/**
* Returns the configured character for the left side of the background.
*
* @return the left-side configured character
*/
ConfiguredCharacter left();
/**
* Returns the configured character for width 1.
*
* @return the configured character for width 1
*/
ConfiguredCharacter width_1();
/**
* Returns the configured character for width 2.
*
* @return the configured character for width 2
*/
ConfiguredCharacter width_2();
/**
* Returns the configured character for width 4.
*
* @return the configured character for width 4
*/
ConfiguredCharacter width_4();
/**
* Returns the configured character for width 8.
*
* @return the configured character for width 8
*/
ConfiguredCharacter width_8();
/**
* Returns the configured character for width 16.
*
* @return the configured character for width 16
*/
ConfiguredCharacter width_16();
/**
* Returns the configured character for width 32.
*
* @return the configured character for width 32
*/
ConfiguredCharacter width_32();
/**
* Returns the configured character for width 64.
*
* @return the configured character for width 64
*/
ConfiguredCharacter width_64();
/**
* Returns the configured character for width 128.
*
* @return the configured character for width 128
*/
ConfiguredCharacter width_128();
/**
* Returns the configured character for the right side of the background.
*
* @return the right-side configured character
*/
ConfiguredCharacter right();
/**
* Creates a new builder for constructing a Background configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new BackgroundImpl.BuilderImpl();
}
/**
* Builder for constructing Background configurations.
*/
interface Builder {
/**
* Sets the unique ID for the background.
*
* @param id the background ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the configured character for the left side of the background.
*
* @param character the configured character for the left side
* @return the builder instance
*/
Builder left(ConfiguredCharacter character);
/**
* Sets the configured character for width 1.
*
* @param character the configured character for width 1
* @return the builder instance
*/
Builder width_1(ConfiguredCharacter character);
/**
* Sets the configured character for width 2.
*
* @param character the configured character for width 2
* @return the builder instance
*/
Builder width_2(ConfiguredCharacter character);
/**
* Sets the configured character for width 4.
*
* @param character the configured character for width 4
* @return the builder instance
*/
Builder width_4(ConfiguredCharacter character);
/**
* Sets the configured character for width 8.
*
* @param character the configured character for width 8
* @return the builder instance
*/
Builder width_8(ConfiguredCharacter character);
/**
* Sets the configured character for width 16.
*
* @param character the configured character for width 16
* @return the builder instance
*/
Builder width_16(ConfiguredCharacter character);
/**
* Sets the configured character for width 32.
*
* @param character the configured character for width 32
* @return the builder instance
*/
Builder width_32(ConfiguredCharacter character);
/**
* Sets the configured character for width 64.
*
* @param character the configured character for width 64
* @return the builder instance
*/
Builder width_64(ConfiguredCharacter character);
/**
* Sets the configured character for width 128.
*
* @param character the configured character for width 128
* @return the builder instance
*/
Builder width_128(ConfiguredCharacter character);
/**
* Sets the configured character for the right side of the background.
*
* @param character the configured character for the right side
* @return the builder instance
*/
Builder right(ConfiguredCharacter character);
/**
* Builds and returns the configured Background instance.
*
* @return the constructed Background
*/
Background build();
}
}
@@ -0,0 +1,327 @@
/*
* Copyright (C) <2022> <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.api.feature.background;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
@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;
}
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
String offset1 = OffsetFont.shortestNegChars(advance + rightMargin + right.advance());
advance = leftMargin + advance + rightMargin;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.character());
while (advance >= 128) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_128.character());
advance -= 128;
}
if (advance - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_64.character());
advance -= 64;
}
if (advance - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_32.character());
advance -= 32;
}
if (advance - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_16.character());
advance -= 16;
}
if (advance - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_8.character());
advance -= 8;
}
if (advance - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_4.character());
advance -= 4;
}
if (advance - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_2.character());
advance -= 2;
}
if (advance - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_1.character());
}
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(right.character());
stringBuilder.append(offset1);
return stringBuilder.toString();
}
@Override
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
return OffsetFont.shortestPosChars(rightMargin + right.advance());
}
@Override
public String createImage(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
advance = advance + leftMargin + rightMargin + 2;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.character());
while (advance >= 128) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_128.character());
advance -= 128;
}
if (advance - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_64.character());
advance -= 64;
}
if (advance - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_32.character());
advance -= 32;
}
if (advance - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_16.character());
advance -= 16;
}
if (advance - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_8.character());
advance -= 8;
}
if (advance - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_4.character());
advance -= 4;
}
if (advance - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_2.character());
advance -= 2;
}
if (advance - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_1.character());
}
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(right.character());
return stringBuilder.toString();
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
BackgroundImpl that = (BackgroundImpl) object;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
public static class BuilderImpl implements Builder {
private String id;
private ConfiguredCharacter left;
private ConfiguredCharacter width_1;
private ConfiguredCharacter width_2;
private ConfiguredCharacter width_4;
private ConfiguredCharacter width_8;
private ConfiguredCharacter width_16;
private ConfiguredCharacter width_32;
private ConfiguredCharacter width_64;
private ConfiguredCharacter width_128;
private ConfiguredCharacter right;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder left(ConfiguredCharacter character) {
this.left = character;
return this;
}
@Override
public Builder width_1(ConfiguredCharacter character) {
this.width_1 = character;
return this;
}
@Override
public Builder width_2(ConfiguredCharacter character) {
this.width_2 = character;
return this;
}
@Override
public Builder width_4(ConfiguredCharacter character) {
this.width_4 = character;
return this;
}
@Override
public Builder width_8(ConfiguredCharacter character) {
this.width_8 = character;
return this;
}
@Override
public Builder width_16(ConfiguredCharacter character) {
this.width_16 = character;
return this;
}
@Override
public Builder width_32(ConfiguredCharacter character) {
this.width_32 = character;
return this;
}
@Override
public Builder width_64(ConfiguredCharacter character) {
this.width_64 = character;
return this;
}
@Override
public Builder width_128(ConfiguredCharacter character) {
this.width_128 = character;
return this;
}
@Override
public Builder right(ConfiguredCharacter character) {
this.right = character;
return this;
}
@Override
public Background build() {
return new BackgroundImpl(id, left, width_1, width_2, width_4, width_8, width_16, width_32, width_64, width_128, right);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* 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
@@ -15,32 +15,28 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
package net.momirealms.customnameplates.api.feature.background;
import net.momirealms.customnameplates.api.mechanic.tag.team.TeamTagPlayer;
import org.bukkit.entity.Player;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.Collection;
public interface TeamTagManager {
public interface BackgroundManager extends Reloadable {
/**
* Create team tag for a player
* If failed, the return value would be null
* This happens when there already exists a team tag for a player
* Retrieves a Background configuration by its unique ID.
*
* @return team tag
* @param id the unique ID of the background
* @return the corresponding Background, or null if not found
*/
@Nullable
TeamTagPlayer createTagForPlayer(Player player, String prefix, String suffix);
Background backgroundById(String id);
/**
* Remove a team tag from map by uuid
* Returns a collection of all available Background configurations.
*
* @param uuid uuid
* @return team tag
* @return a collection of Background instances
*/
@Nullable
TeamTagPlayer removeTeamPlayerFromMap(UUID uuid);
Collection<Background> getBackgrounds();
}
@@ -0,0 +1,70 @@
/*
* 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.api.feature.bossbar;
import java.util.UUID;
public interface BossBar {
/**
* Returns the unique UUID of the BossBar.
*
* @return the UUID of the BossBar
*/
UUID uuid();
/**
* Returns the progress value of the BossBar.
* The value should be between 0.0 (empty) and 1.0 (full).
*
* @return the progress value of the BossBar
*/
float progress();
/**
* Returns the color of the BossBar.
*
* @return the color of the BossBar
*/
Color color();
/**
* Returns the overlay style of the BossBar, defining how the bar is divided.
*
* @return the overlay style of the BossBar
*/
Overlay overlay();
enum Overlay {
PROGRESS,
NOTCHED_6,
NOTCHED_10,
NOTCHED_12,
NOTCHED_20
}
enum Color {
BLUE,
GREEN,
PINK,
PURPLE,
RED,
WHITE,
YELLOW
}
}
@@ -0,0 +1,147 @@
/*
* 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.api.feature.bossbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
public interface BossBarConfig {
/**
* The default overlay style for the BossBar.
*/
BossBar.Overlay DEFAULT_OVERLAY = BossBar.Overlay.PROGRESS;
/**
* The default color for the BossBar.
*/
BossBar.Color DEFAULT_COLOR = BossBar.Color.YELLOW;
/**
* Returns the unique ID for the BossBar configuration.
*
* @return the configuration ID
*/
String id();
/**
* Returns the requirements for the BossBar.
*
* @return an array of requirements
*/
Requirement[] requirements();
/**
* Returns the carousel texts used in the BossBar.
*
* @return an array of carousel texts
*/
CarouselText[] carouselTexts();
/**
* Returns the overlay style for the BossBar.
*
* @return the overlay style
*/
BossBar.Overlay overlay();
/**
* Returns the color of the BossBar.
*
* @return the BossBar color
*/
BossBar.Color color();
/**
* Returns the progress value of the BossBar.
* The value should be between 0.0 (empty) and 1.0 (full).
*
* @return the progress value
*/
float progress();
/**
* Creates a new builder for constructing a BossBarConfig.
*
* @return a new builder instance
*/
static BossBarConfig.Builder builder() {
return new BossBarConfigImpl.BuilderImpl();
}
/**
* Builder for constructing BossBarConfig instances.
*/
interface Builder {
/**
* Sets the unique ID for the BossBar configuration.
*
* @param id the configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the requirements for the BossBar.
*
* @param requirements an array of requirements
* @return the builder instance
*/
Builder requirement(Requirement[] requirements);
/**
* Sets the carousel texts for the BossBar.
*
* @param carouselTexts an array of carousel texts
* @return the builder instance
*/
Builder carouselText(CarouselText[] carouselTexts);
/**
* Sets the overlay style for the BossBar.
*
* @param overlay the overlay style
* @return the builder instance
*/
Builder overlay(BossBar.Overlay overlay);
/**
* Sets the color for the BossBar.
*
* @param color the BossBar color
* @return the builder instance
*/
Builder color(BossBar.Color color);
/**
* Sets the progress value for the BossBar.
*
* @param progress the progress value
* @return the builder instance
*/
Builder progress(float progress);
/**
* Builds and returns the configured BossBarConfig instance.
*
* @return the constructed BossBarConfig
*/
BossBarConfig build();
}
}
@@ -0,0 +1,123 @@
/*
* 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.api.feature.bossbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import static java.util.Objects.requireNonNull;
public class BossBarConfigImpl implements BossBarConfig {
private final String id;
private final Requirement[] requirements;
private final CarouselText[] carouselTexts;
private final BossBar.Overlay overlay;
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) {
this.id = requireNonNull(id);
this.requirements = requireNonNull(requirements);
this.carouselTexts = requireNonNull(carouselTexts);
this.overlay = requireNonNull(overlay);
this.color = requireNonNull(color);
this.progress = progress;
}
@Override
public String id() {
return id;
}
@Override
public Requirement[] requirements() {
return requirements;
}
@Override
public CarouselText[] carouselTexts() {
return carouselTexts;
}
@Override
public BossBar.Overlay overlay() {
return overlay;
}
@Override
public BossBar.Color color() {
return color;
}
@Override
public float progress() {
return progress;
}
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] requirements;
private CarouselText[] carouselTexts;
private BossBar.Overlay overlay = DEFAULT_OVERLAY;
private BossBar.Color color = DEFAULT_COLOR;
private float progress = 0f;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder requirement(Requirement[] requirements) {
this.requirements = requirements;
return this;
}
@Override
public Builder carouselText(CarouselText[] carouselTexts) {
this.carouselTexts = carouselTexts;
return this;
}
@Override
public Builder overlay(BossBar.Overlay overlay) {
this.overlay = overlay;
return this;
}
@Override
public Builder color(BossBar.Color color) {
this.color = color;
return this;
}
@Override
public Builder progress(float progress) {
this.progress = progress;
return this;
}
@Override
public BossBarConfig build() {
return new BossBarConfigImpl(id, requirements, carouselTexts, overlay, color, progress);
}
}
}
@@ -0,0 +1,43 @@
/*
* 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.api.feature.bossbar;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
public interface BossBarManager extends Reloadable {
/**
* Retrieves the BossBar configuration by its id.
*
* @param id the name of the BossBar configuration
* @return the corresponding BossBarConfig, or null if not found
*/
BossBarConfig configById(String id);
/**
* Returns all available BossBar configurations.
*
* @return an array of all BossBarConfig instances
*/
BossBarConfig[] bossBarConfigs();
/**
* Called on every server tick to update the state of BossBars.
*/
void onTick();
}
@@ -0,0 +1,121 @@
/*
* 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.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
public interface Bubble extends AdaptiveImage {
/**
* Returns the unique ID of the Bubble configuration.
*
* @return the Bubble ID
*/
String id();
/**
* Returns the configured character for the left side of the Bubble.
*
* @return the left-side configured character
*/
ConfiguredCharacter left();
/**
* Returns the configured character for the right side of the Bubble.
*
* @return the right-side configured character
*/
ConfiguredCharacter right();
/**
* Returns the configured character for the middle section of the Bubble.
*
* @return the middle configured character
*/
ConfiguredCharacter middle();
/**
* Returns the configured character for the tail section of the Bubble.
*
* @return the tail configured character
*/
ConfiguredCharacter tail();
/**
* Creates a new builder for constructing a Bubble configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new BubbleImpl.BuilderImpl();
}
/**
* Builder for constructing Bubble configurations.
*/
interface Builder {
/**
* Sets the unique ID for the Bubble configuration.
*
* @param id the Bubble ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the configured character for the left side of the Bubble.
*
* @param left the left-side configured character
* @return the builder instance
*/
Builder left(ConfiguredCharacter left);
/**
* Sets the configured character for the right side of the Bubble.
*
* @param right the right-side configured character
* @return the builder instance
*/
Builder right(ConfiguredCharacter right);
/**
* Sets the configured character for the middle section of the Bubble.
*
* @param middle the middle configured character
* @return the builder instance
*/
Builder middle(ConfiguredCharacter middle);
/**
* Sets the configured character for the tail section of the Bubble.
*
* @param tail the tail configured character
* @return the builder instance
*/
Builder tail(ConfiguredCharacter tail);
/**
* Builds and returns the constructed Bubble instance.
*
* @return the constructed Bubble
*/
Bubble build();
}
}
@@ -0,0 +1,180 @@
/*
* 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.api.feature.bubble;
import net.momirealms.customnameplates.api.util.Vector3;
public interface BubbleConfig {
/**
* Returns the unique ID of the Bubble configuration.
*
* @return the configuration ID
*/
String id();
/**
* Returns the background color of the Bubble text.
*
* @return the background color (ARGB) as an integer
*/
int backgroundColor();
/**
* Returns the line width for the Bubble text.
*
* @return the line width
*/
int lineWidth();
/**
* Returns the maximum number of lines for the Bubble text.
*
* @return the maximum number of lines
*/
int maxLines();
/**
* Returns the bubbles used in this configuration.
*
* @return an array of Bubble instances
*/
Bubble[] bubbles();
/**
* Returns the text prefix to be applied before the Bubble content.
*
* @return the text prefix
*/
String textPrefix();
/**
* Returns the text suffix to be applied after the Bubble content.
*
* @return the text suffix
*/
String textSuffix();
/**
* Returns the display name of the Bubble.
*
* @return the display name
*/
String displayName();
/**
* Returns the scale vector for the Bubble.
*
* @return the scale as a Vector3
*/
Vector3 scale();
/**
* Creates a new builder for constructing a BubbleConfig.
*
* @return a new builder instance
*/
static Builder builder() {
return new BubbleConfigImpl.BuilderImpl();
}
/**
* Builder for constructing BubbleConfig instances.
*/
interface Builder {
/**
* Sets the unique ID for the BubbleConfig.
*
* @param id the configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the display name for the BubbleConfig.
*
* @param displayName the display name
* @return the builder instance
*/
Builder displayName(String displayName);
/**
* Sets the background color for the BubbleConfig.
*
* @param backgroundColor the background color
* @return the builder instance
*/
Builder backgroundColor(int backgroundColor);
/**
* Sets the line width for the Bubble text.
*
* @param lineWidth the line width
* @return the builder instance
*/
Builder lineWidth(int lineWidth);
/**
* Sets the maximum number of lines for the Bubble text.
*
* @param maxLines the maximum number of lines
* @return the builder instance
*/
Builder maxLines(int maxLines);
/**
* Sets the bubbles used in this configuration.
*
* @param bubbles an array of Bubble instances
* @return the builder instance
*/
Builder bubbles(Bubble[] bubbles);
/**
* Sets the text prefix for the BubbleConfig.
*
* @param textPrefix the text prefix
* @return the builder instance
*/
Builder textPrefix(String textPrefix);
/**
* Sets the text suffix for the BubbleConfig.
*
* @param textSuffix the text suffix
* @return the builder instance
*/
Builder textSuffix(String textSuffix);
/**
* Sets the scale for the BubbleConfig.
*
* @param scale the scale as a Vector3
* @return the builder instance
*/
Builder scale(Vector3 scale);
/**
* Builds and returns the configured BubbleConfig instance.
*
* @return the constructed BubbleConfig
*/
BubbleConfig build();
}
}
@@ -0,0 +1,164 @@
/*
* 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.api.feature.bubble;
import net.momirealms.customnameplates.api.util.Vector3;
import static java.util.Objects.requireNonNull;
public class BubbleConfigImpl implements BubbleConfig {
private final String id;
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 String displayName;
private final Vector3 scale;
public BubbleConfigImpl(String id, String displayName, int backgroundColor, int lineWidth, int maxLines, Bubble[] bubbles, String textPrefix, String textSuffix, Vector3 scale) {
this.backgroundColor = backgroundColor;
this.lineWidth = lineWidth;
this.maxLines = maxLines;
this.id = id;
this.bubbles = requireNonNull(bubbles);
this.textPrefix = requireNonNull(textPrefix);
this.textSuffix = requireNonNull(textSuffix);
this.displayName = requireNonNull(displayName);
this.scale = requireNonNull(scale);
}
@Override
public String id() {
return id;
}
@Override
public int backgroundColor() {
return backgroundColor;
}
@Override
public int lineWidth() {
return lineWidth;
}
@Override
public int maxLines() {
return maxLines;
}
@Override
public Bubble[] bubbles() {
return bubbles;
}
@Override
public String textPrefix() {
return textPrefix;
}
@Override
public String textSuffix() {
return textSuffix;
}
@Override
public String displayName() {
return displayName;
}
@Override
public Vector3 scale() {
return scale;
}
public static class BuilderImpl implements Builder {
private int backgroundColor;
private int lineWidth;
private int maxLines;
private Bubble[] bubbles;
private String textPrefix;
private String textSuffix;
private String id;
private String displayName;
private Vector3 scale;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder displayName(String displayName) {
this.displayName = displayName;
return this;
}
@Override
public Builder backgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
@Override
public Builder lineWidth(int lineWidth) {
this.lineWidth = lineWidth;
return this;
}
@Override
public Builder maxLines(int maxLines) {
this.maxLines = maxLines;
return this;
}
@Override
public Builder bubbles(Bubble[] bubbles) {
this.bubbles = bubbles;
return this;
}
@Override
public Builder textPrefix(String textPrefix) {
this.textPrefix = textPrefix;
return this;
}
@Override
public Builder textSuffix(String textSuffix) {
this.textSuffix = textSuffix;
return this;
}
@Override
public Builder scale(Vector3 scale) {
this.scale = scale;
return this;
}
@Override
public BubbleConfig build() {
return new BubbleConfigImpl(id, displayName, backgroundColor, lineWidth, maxLines, bubbles, textPrefix, textSuffix, scale);
}
}
}
@@ -0,0 +1,195 @@
/*
* 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.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
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;
public BubbleImpl(String id, ConfiguredCharacter left, ConfiguredCharacter right, ConfiguredCharacter middle, ConfiguredCharacter tail) {
this.id = id;
this.left = left;
this.right = right;
this.middle = middle;
this.tail = tail;
}
@Override
public String id() {
return id;
}
@Override
public ConfiguredCharacter left() {
return left;
}
@Override
public ConfiguredCharacter right() {
return right;
}
@Override
public ConfiguredCharacter middle() {
return middle;
}
@Override
public ConfiguredCharacter tail() {
return tail;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
BubbleImpl bubble = (BubbleImpl) object;
return Objects.equals(id, bubble.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
float actualMiddleWidth = 0;
if (mid_amount > 512) return "";
if (mid_amount <= 0) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
actualMiddleWidth = tail.advance() - 1;
} else {
actualMiddleWidth += (middle.advance() - 1) * mid_amount;
actualMiddleWidth += (tail.advance() - 1);
int tailPos = mid_amount / 2;
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
if (i == tailPos) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
}
}
}
float exceed = actualMiddleWidth - advance;
sb.append(right.character());
float delta = (right.advance() + rightMargin + advance + exceed / 2);
if (delta != 0) {
sb.append(OffsetFont.createOffsets(-delta));
}
return sb.toString();
}
@Override
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
float actualMiddleWidth = 0;
actualMiddleWidth += (tail.advance() - 1);
actualMiddleWidth += (middle.advance() - 1) * mid_amount;
float exceed = actualMiddleWidth - advance;
float delta = (right.advance() + rightMargin + exceed / 2);
return OffsetFont.shortestPosChars(delta);
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImage(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
if (mid_amount > 512) return "";
if (mid_amount <= 0) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
} else {
int tailPos = mid_amount / 2;
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
if (i == tailPos) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
}
}
}
sb.append(right.character());
float delta = (right.advance() + rightMargin - (left.advance() - 1) - leftMargin);
if (delta != 0) {
sb.append(OffsetFont.createOffsets(-delta));
}
return sb.toString();
}
public static class BuilderImpl implements Builder {
private String id;
private ConfiguredCharacter left;
private ConfiguredCharacter right;
private ConfiguredCharacter middle;
private ConfiguredCharacter tail;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder left(ConfiguredCharacter left) {
this.left = left;
return this;
}
@Override
public Builder right(ConfiguredCharacter right) {
this.right = right;
return this;
}
@Override
public Builder middle(ConfiguredCharacter middle) {
this.middle = middle;
return this;
}
@Override
public Builder tail(ConfiguredCharacter tail) {
this.tail = tail;
return this;
}
@Override
public Bubble build() {
return new BubbleImpl(id, left, right, middle, tail);
}
}
}
@@ -0,0 +1,148 @@
/*
* 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.api.feature.bubble;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
public interface BubbleManager extends Reloadable {
/**
* Returns a collection of all available Bubble instances.
*
* @return a collection of Bubble instances
*/
Collection<Bubble> bubbles();
/**
* Returns a collection of all Bubble configurations.
*
* @return a collection of BubbleConfig instances
*/
Collection<BubbleConfig> bubbleConfigs();
/**
* Retrieves a Bubble by its unique ID.
*
* @param id the Bubble ID
* @return the Bubble instance, or null if not found
*/
@Nullable
Bubble bubbleById(String id);
/**
* Retrieves a Bubble configuration by its unique ID.
*
* @param id the BubbleConfig ID
* @return the BubbleConfig instance, or null if not found
*/
@Nullable
BubbleConfig bubbleConfigById(String id);
/**
* Checks if a player has access to a specific Bubble by its ID.
*
* @param player the player to check
* @param id the Bubble ID
* @return true if the player has the Bubble, false otherwise
*/
boolean hasBubble(CNPlayer player, String id);
/**
* Returns a collection of available Bubbles for the player.
*
* @param player the player to check
* @return a collection of available BubbleConfig instances
*/
Collection<BubbleConfig> availableBubbles(CNPlayer player);
/**
* Returns the set of channels that are blacklisted from displaying Bubbles.
*
* @return a set of blacklisted channel names
*/
Set<String> blacklistChannels();
/**
* Returns the current mode for Bubble channels.
*
* @return the ChannelMode in use
*/
ChannelMode channelMode();
/**
* Returns the default Bubble ID used when no specific Bubble is set.
*
* @return the default Bubble ID
*/
String defaultBubbleId();
/**
* Returns the requirements to send a Bubble.
*
* @return an array of send Bubble requirements
*/
Requirement[] sendBubbleRequirements();
/**
* Returns the requirements to view a Bubble.
*
* @return an array of view Bubble requirements
*/
Requirement[] viewBubbleRequirements();
/**
* Returns the vertical offset for Bubble display.
*
* @return the vertical offset as a double
*/
double verticalOffset();
/**
* Returns the duration (in ticks) for which the Bubble remains visible.
*
* @return the stay duration in ticks
*/
int stayDuration();
/**
* Returns the duration (in ticks) for the Bubble to appear.
*
* @return the appear duration in ticks
*/
int appearDuration();
/**
* Returns the duration (in ticks) for the Bubble to disappear.
*
* @return the disappear duration in ticks
*/
int disappearDuration();
/**
* Returns the view range for Bubbles.
*
* @return the view range as a float
*/
float viewRange();
}
@@ -15,8 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
package net.momirealms.customnameplates.api.feature.bubble;
public interface BossBarManager {
public enum ChannelMode {
ALL,
JOINED,
CAN_JOIN
}
@@ -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.api.feature.chat;
import net.momirealms.customnameplates.api.CustomNameplates;
/**
* Abstract base class for chat message providers, providing common functionality
* for managing the plugin and chat manager.
*/
public abstract class AbstractChatMessageProvider implements ChatMessageProvider {
protected CustomNameplates plugin;
protected ChatManager manager;
/**
* Constructs a new AbstractChatMessageProvider.
*
* @param plugin the CustomNameplates plugin instance
* @param manager the ChatManager instance to handle chat-related operations
*/
public AbstractChatMessageProvider(CustomNameplates plugin, ChatManager manager) {
this.plugin = plugin;
this.manager = manager;
}
/**
* Registers the chat message provider. Intended to be overridden by subclasses if needed.
*/
public void register() {
}
/**
* Unregisters the chat message provider. Intended to be overridden by subclasses if needed.
*/
public void unregister() {
}
}
@@ -0,0 +1,73 @@
/*
* 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.api.feature.chat;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.feature.ChatListener;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
/**
* Manages chat-related functionality, including handling custom chat providers, listeners, and chat events.
*/
public interface ChatManager extends Reloadable {
/**
* Sets a custom chat message provider.
*
* @param provider the custom ChatMessageProvider to set
* @return true if the provider was successfully set, false otherwise
*/
boolean setCustomChatProvider(ChatMessageProvider provider);
/**
* Removes the currently set custom chat message provider.
*
* @return true if the provider was successfully removed, false otherwise
*/
boolean removeCustomChatProvider();
/**
* Registers a chat listener to receive chat events.
*
* @param listener the ChatListener to register
*/
void registerListener(ChatListener listener);
/**
* Unregisters a chat listener, stopping it from receiving chat events.
*
* @param listener the ChatListener to unregister
*/
void unregisterListener(ChatListener listener);
/**
* Returns the current chat message provider.
*
* @return the currently set ChatMessageProvider, or null if none is set
*/
ChatMessageProvider chatProvider();
/**
* Handles a chat message event for the specified player and channel.
*
* @param player the player who sent the message
* @param message the chat message content
* @param channel the chat channel
*/
void onChat(CNPlayer player, String message, String channel);
}
@@ -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.api.feature.chat;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Provides chat-related functionality, including channel membership and ignore status between players.
*/
public interface ChatMessageProvider {
/**
* Checks if a player has joined a specific chat channel.
*
* @param player the player to check
* @param channelID the ID of the chat channel
* @return true if the player has joined the channel, false otherwise
*/
boolean hasJoinedChannel(CNPlayer player, String channelID);
/**
* Checks if a player is allowed to join a specific chat channel.
*
* @param player the player to check
* @param channelID the ID of the chat channel
* @return true if the player can join the channel, false otherwise
*/
boolean canJoinChannel(CNPlayer player, String channelID);
/**
* Checks if a player is ignoring another player.
*
* @param sender the player sending messages
* @param receiver the player who may be ignoring the sender
* @return true if the receiver is ignoring the sender, false otherwise
*/
boolean isIgnoring(CNPlayer sender, CNPlayer receiver);
}
@@ -0,0 +1,36 @@
/*
* 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.api.feature.chat.emoji;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Interface for providing emoji replacement functionality.
* Allows replacing certain text patterns with corresponding emojis for a given player.
*/
public interface EmojiProvider {
/**
* Replaces specified text patterns in the given string with emojis, based on the player context.
*
* @param player the player for whom the emoji replacement is being processed
* @param text the original text to process
* @return the text with emojis replacing certain patterns
*/
String replace(CNPlayer player, String text);
}
@@ -0,0 +1,106 @@
/*
* 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.api.feature.image;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
public interface Image {
/**
* Returns the unique ID of the image configuration.
*
* @return the image ID
*/
String id();
/**
* Checks if the image has a shadow effect.
*
* @return true if the image has a shadow, false otherwise
*/
boolean hasShadow();
/**
* Returns the opacity level of the image.
* The value should typically range from 0 (fully transparent) to 255 (fully opaque).
*
* @return the opacity value of the image
*/
int opacity();
/**
* Returns the configured character associated with this image.
*
* @return the configured character
*/
ConfiguredCharacter character();
/**
* Creates a new builder for constructing an Image configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new ImageImpl.BuilderImpl();
}
/**
* Builder for constructing Image configurations.
*/
interface Builder {
/**
* Sets the unique ID for the image configuration.
*
* @param id the image ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets whether the image has a shadow effect.
*
* @param has true if the image should have a shadow, false otherwise
* @return the builder instance
*/
Builder hasShadow(boolean has);
/**
* Sets the opacity level of the image.
*
* @param opacity the opacity value, typically from 0 to 255
* @return the builder instance
*/
Builder opacity(int opacity);
/**
* Sets the configured character associated with this image.
*
* @param character the configured character
* @return the builder instance
*/
Builder character(ConfiguredCharacter character);
/**
* Builds and returns the configured Image instance.
*
* @return the constructed Image
*/
Image build();
}
}
@@ -0,0 +1,107 @@
/*
* 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.api.feature.image;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import java.util.Objects;
public class ImageImpl implements Image {
private final String id;
private final boolean hasShadow;
private final int opacity;
private final ConfiguredCharacter character;
public ImageImpl(String id, boolean hasShadow, int opacity, ConfiguredCharacter character) {
this.id = id;
this.hasShadow = hasShadow;
this.opacity = opacity;
this.character = character;
}
@Override
public String id() {
return id;
}
@Override
public boolean hasShadow() {
return hasShadow;
}
@Override
public int opacity() {
return opacity;
}
@Override
public ConfiguredCharacter character() {
return character;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
ImageImpl image = (ImageImpl) object;
return Objects.equals(id, image.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
public static class BuilderImpl implements Builder {
private String id;
private boolean hasShadow;
private int opacity;
private ConfiguredCharacter character;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder hasShadow(boolean has) {
this.hasShadow = has;
return this;
}
@Override
public Builder opacity(int opacity) {
this.opacity = opacity;
return this;
}
@Override
public Builder character(ConfiguredCharacter character) {
this.character = character;
return this;
}
@Override
public Image build() {
return new ImageImpl(id, hasShadow, opacity, character);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* 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
@@ -15,18 +15,28 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.velocity.team;
package net.momirealms.customnameplates.api.feature.image;
import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.text.Component;
import net.momirealms.customnameplates.common.team.TeamColor;
import net.momirealms.customnameplates.common.team.TeamTagVisibility;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
public interface VelocityTeamManager {
import java.util.Collection;
public interface ImageManager extends Reloadable {
/**
* Retrieves an Image configuration by its unique ID.
*
* @param id the unique ID of the image
* @return the Image instance, or null if not found
*/
@Nullable
String getTeam(Player player, Player viewer);
Image imageById(String id);
void sendTeamUpdatePacket(Player receiver, String team, TeamColor color, TeamTagVisibility visibility, Component prefix, Component suffix);
/**
* Returns a collection of all available Image configurations.
*
* @return a collection of Image instances
*/
Collection<Image> images();
}
@@ -0,0 +1,121 @@
/*
* 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.api.feature.nameplate;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
public interface Nameplate extends AdaptiveImage {
/**
* Returns the unique ID of the nameplate configuration.
*
* @return the nameplate ID
*/
String id();
/**
* Returns the display name of the nameplate.
*
* @return the display name of the nameplate
*/
String displayName();
/**
* Returns the configured character for the left side of the nameplate.
*
* @return the left-side configured character
*/
ConfiguredCharacter left();
/**
* Returns the configured character for the middle section of the nameplate.
*
* @return the middle configured character
*/
ConfiguredCharacter middle();
/**
* Returns the configured character for the right side of the nameplate.
*
* @return the right-side configured character
*/
ConfiguredCharacter right();
/**
* Creates a new builder for constructing a Nameplate configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new NameplateImpl.BuilderImpl();
}
/**
* Builder for constructing Nameplate configurations.
*/
interface Builder {
/**
* Sets the unique ID for the nameplate.
*
* @param id the nameplate ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the display name for the nameplate.
*
* @param displayName the display name
* @return the builder instance
*/
Builder displayName(String displayName);
/**
* Sets the configured character for the left side of the nameplate.
*
* @param left the left-side configured character
* @return the builder instance
*/
Builder left(ConfiguredCharacter left);
/**
* Sets the configured character for the middle section of the nameplate.
*
* @param middle the middle configured character
* @return the builder instance
*/
Builder middle(ConfiguredCharacter middle);
/**
* Sets the configured character for the right side of the nameplate.
*
* @param right the right-side configured character
* @return the builder instance
*/
Builder right(ConfiguredCharacter right);
/**
* Builds and returns the configured Nameplate instance.
*
* @return the constructed Nameplate
*/
Nameplate build();
}
}
@@ -0,0 +1,170 @@
/*
* 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.api.feature.nameplate;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
public class NameplateImpl implements Nameplate {
private final String id;
private final String displayName;
private final ConfiguredCharacter left;
private final ConfiguredCharacter middle;
private final ConfiguredCharacter right;
public NameplateImpl(String id, String displayName, ConfiguredCharacter left, ConfiguredCharacter middle, ConfiguredCharacter right) {
this.id = id;
this.displayName = displayName;
this.left = left;
this.middle = middle;
this.right = right;
}
@Override
public String id() {
return id;
}
@Override
public String displayName() {
return displayName;
}
@Override
public ConfiguredCharacter left() {
return left;
}
@Override
public ConfiguredCharacter middle() {
return middle;
}
@Override
public ConfiguredCharacter right() {
return right;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
NameplateImpl nameplate = (NameplateImpl) object;
return Objects.equals(id, nameplate.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin) / (middle.advance() - 1));
float exceed = mid_amount * (middle.advance() - 1) - advance - leftMargin - rightMargin;
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
}
sb.append(right.character());
float delta = (right.advance() + rightMargin + advance + (float) Math.floor(exceed / 2));
if (delta != 0) {
sb.append(OffsetFont.shortestNegChars(delta));
}
return sb.toString();
}
@Override
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin) / (middle.advance() - 1));
float exceed = mid_amount * (middle.advance() - 1) - advance - leftMargin - rightMargin;
return OffsetFont.shortestPosChars((float) Math.ceil(exceed / 2) + rightMargin + right.advance());
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImage(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin) / (middle.advance() - 1));
if (mid_amount > 512) return "";
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
}
sb.append(right.character());
float delta = (right.advance() + rightMargin - (left.advance() - 1) - leftMargin);
if (delta != 0) {
sb.append(OffsetFont.createOffsets(-delta));
}
return sb.toString();
}
public static class BuilderImpl implements Builder {
private String id;
private String displayName;
private ConfiguredCharacter left;
private ConfiguredCharacter middle;
private ConfiguredCharacter right;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder displayName(String displayName) {
this.displayName = displayName;
return this;
}
@Override
public Builder left(ConfiguredCharacter left) {
this.left = left;
return this;
}
@Override
public Builder middle(ConfiguredCharacter middle) {
this.middle = middle;
return this;
}
@Override
public Builder right(ConfiguredCharacter right) {
this.right = right;
return this;
}
@Override
public Nameplate build() {
return new NameplateImpl(id, displayName, left, middle, right);
}
}
}
@@ -0,0 +1,74 @@
/*
* 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.api.feature.nameplate;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface NameplateManager extends Reloadable {
/**
* Retrieves a Nameplate by its unique ID.
*
* @param id the unique ID of the nameplate
* @return the Nameplate instance, or null if not found
*/
@Nullable
Nameplate nameplateById(String id);
/**
* Returns a collection of all available nameplates.
*
* @return a collection of Nameplate instances
*/
Collection<Nameplate> nameplates();
/**
* Checks if a player has access to a specific nameplate by its ID.
*
* @param player the player to check
* @param id the ID of the nameplate
* @return true if the player has access, false otherwise
*/
boolean hasNameplate(CNPlayer player, String id);
/**
* Returns a collection of nameplates available to the player.
*
* @param player the player to check
* @return a collection of available Nameplate instances
*/
Collection<Nameplate> availableNameplates(CNPlayer player);
/**
* Returns the ID of the default nameplate to be used when no specific nameplate is set.
*
* @return the default nameplate ID
*/
String defaultNameplateId();
/**
* Returns the player's name tag to be displayed on the nameplate.
*
* @return the player's name tag
*/
String playerNameTag();
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* 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
@@ -15,19 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.scheduler;
package net.momirealms.customnameplates.api.feature.pack;
public interface CancellableTask {
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
public interface ResourcePackManager extends Reloadable {
/**
* Cancel the task
* Generates the resource pack.
*/
void cancel();
/**
* Get if the task is cancelled or not
*
* @return cancelled or not
*/
boolean isCancelled();
void generate();
}
@@ -0,0 +1,209 @@
/*
* 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.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.CustomNameplates;
import net.momirealms.customnameplates.api.network.Tracker;
import net.momirealms.customnameplates.api.util.SelfIncreaseEntityID;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.Vector;
import java.util.function.Consumer;
public abstract class AbstractTag implements Tag {
protected CNPlayer owner;
protected TagRenderer renderer;
protected final UUID uuid = UUID.randomUUID();
protected final int entityID = SelfIncreaseEntityID.getAndIncrease();
protected boolean isShown = false;
protected final Vector<CNPlayer> viewers = new Vector<>();
protected CNPlayer[] viewerArray = new CNPlayer[0];
public AbstractTag(CNPlayer owner, TagRenderer renderer) {
this.owner = owner;
this.renderer = renderer;
}
protected abstract List<Object> spawnPacket(CNPlayer viewer);
@Override
public void tick() {
}
@Override
public void init() {
}
@Override
public boolean canShow() {
return true;
}
@Override
public boolean canShow(CNPlayer viewer) {
return true;
}
@Override
public void show() {
if (isShown) return;
this.isShown = true;
for (CNPlayer viewer : viewerArray) {
show(viewer);
}
}
@Override
public void show(CNPlayer viewer) {
if (!isShown()) throw new IllegalStateException("This tag is currently hidden");
viewers.add(viewer);
resetViewerArray();
owner.trackPassengers(viewer, entityID);
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, spawnPacket(viewer));
}
@Override
public void hide() {
if (!isShown()) return;
for (CNPlayer viewer : viewerArray) {
hide(viewer);
}
this.isShown = false;
}
@Override
public void hide(CNPlayer viewer) {
if (!isShown()) return;
boolean removed = viewers.remove(viewer);
if (!removed) return;
resetViewerArray();
owner.untrackPassengers(viewer, entityID);
Object packet = CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID);
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
@Override
public void respawn(CNPlayer viewer) {
ArrayList<Object> packets = new ArrayList<>();
packets.add(CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID));
packets.addAll(spawnPacket(viewer));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packets);
}
@Override
public void respawn() {
for (CNPlayer viewer : viewerArray) {
respawn(viewer);
}
}
@Override
public void darkTag(boolean dark) {
for (CNPlayer viewer : viewerArray) {
darkTag(viewer, dark);
}
}
@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) {
onPlayerScaleUpdate(viewer, scale);
}
}
@Override
public void onPlayerScaleUpdate(CNPlayer viewer, double scale) {
Consumer<List<Object>> modifier1 = CustomNameplates.getInstance().getPlatform().createScaleModifier(scale(viewer).multiply(scale));
Consumer<List<Object>> modifier2 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(viewer).multiply(scale));
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier1, modifier2));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
@Override
public void updateTranslation() {
for (CNPlayer player : viewerArray) {
updateTranslation(player);
}
}
@Override
public void updateTranslation(CNPlayer viewer) {
Tracker tracker = owner.getTracker(viewer);
if (tracker != null) {
Consumer<List<Object>> modifier = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(viewer).multiply(tracker.getScale()));
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AbstractTag that = (AbstractTag) o;
return owner == that.owner && uuid == that.uuid;
}
@Override
public int hashCode() {
return uuid.hashCode();
}
@Override
public int entityID() {
return entityID;
}
@Override
public UUID uuid() {
return uuid;
}
protected void resetViewerArray() {
this.viewerArray = viewers.toArray(new CNPlayer[0]);
}
@Override
public boolean isShown() {
return isShown;
}
@Override
public boolean isShown(CNPlayer another) {
if (!isShown) return false;
return viewers.contains(another);
}
@Override
public byte opacity() {
return -1;
}
}
@@ -0,0 +1,334 @@
/*
* 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.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.Vector3;
public interface NameTagConfig {
/**
* Returns the unique ID of the name tag configuration.
*
* @return the name tag configuration ID
*/
String id();
/**
* Returns the requirements for the name tag owner.
*
* @return an array of owner requirements
*/
Requirement[] ownerRequirements();
/**
* Returns the requirements for the name tag viewer.
*
* @return an array of viewer requirements
*/
Requirement[] viewerRequirements();
/**
* Returns the carousel texts displayed on the name tag.
*
* @return an array of carousel texts
*/
CarouselText[] carouselTexts();
/**
* Returns the opacity level of the name tag.
*
* @return the opacity value as a byte
*/
byte opacity();
/**
* Returns the background color of the name tag.
*
* @return the background color as an integer
*/
int backgroundColor();
/**
* Checks if the name tag has a shadow effect.
*
* @return true if the name tag has a shadow, false otherwise
*/
boolean hasShadow();
/**
* Checks if the name tag is see-through.
*
* @return true if the name tag is see-through, false otherwise
*/
boolean isSeeThrough();
/**
* Checks if the default background color is used.
*
* @return true if the default background color is used, false otherwise
*/
boolean useDefaultBackgroundColor();
/**
* Checks if the name tag is affected by the crouching state of the player.
*
* @return true if affected by crouching, false otherwise
*/
boolean affectedByCrouching();
/**
* Checks if the name tag is affected by scaling.
*
* @return true if affected by scaling, false otherwise
*/
boolean affectedByScaling();
/**
* Checks if the name tag is affected by spectator mode.
*
* @return true if affected by spectator mode, false otherwise
*/
boolean affectedBySpectator();
/**
* Returns the alignment of the name tag.
*
* @return the alignment of the name tag
*/
Alignment alignment();
/**
* Returns the view range of the name tag.
*
* @return the view range as a float
*/
float viewRange();
/**
* Returns the shadow radius of the name tag.
*
* @return the shadow radius as a float
*/
float shadowRadius();
/**
* Returns the shadow strength of the name tag.
*
* @return the shadow strength as a float
*/
float shadowStrength();
/**
* Returns the scaling vector of the name tag.
*
* @return the scaling vector as a Vector3
*/
Vector3 scale();
/**
* Returns the translation vector for the name tag.
*
* @return the translation vector as a Vector3
*/
Vector3 translation();
/**
* Returns the maximum line width of the name tag.
*
* @return the line width as an integer
*/
int lineWidth();
/**
* Creates a new builder for constructing a NameTagConfig.
*
* @return a new builder instance
*/
static Builder builder() {
return new NameTagConfigImpl.BuilderImpl();
}
/**
* Builder for constructing NameTagConfig instances with customizable properties.
*/
interface Builder {
/**
* Sets the unique ID for the NameTagConfig.
*
* @param id the name tag configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the maximum line width for the name tag.
*
* @param lineWidth the maximum line width
* @return the builder instance
*/
Builder lineWidth(int lineWidth);
/**
* Sets the requirements for the name tag owner.
*
* @param requirements an array of owner requirements
* @return the builder instance
*/
Builder ownerRequirement(Requirement[] requirements);
/**
* Sets the requirements for the name tag viewer.
*
* @param requirements an array of viewer requirements
* @return the builder instance
*/
Builder viewerRequirement(Requirement[] requirements);
/**
* Sets the carousel texts for the name tag.
*
* @param carouselTexts an array of carousel texts
* @return the builder instance
*/
Builder carouselText(CarouselText[] carouselTexts);
/**
* Sets the opacity level for the name tag.
*
* @param opacity the opacity value as a byte
* @return the builder instance
*/
Builder opacity(byte opacity);
/**
* Sets the background color for the name tag.
*
* @param backgroundColor the background color as an integer
* @return the builder instance
*/
Builder backgroundColor(int backgroundColor);
/**
* Sets whether the name tag has a shadow effect.
*
* @param hasShadow true if the name tag should have a shadow, false otherwise
* @return the builder instance
*/
Builder hasShadow(boolean hasShadow);
/**
* Sets whether the name tag is see-through.
*
* @param seeThrough true if the name tag is see-through, false otherwise
* @return the builder instance
*/
Builder seeThrough(boolean seeThrough);
/**
* Sets whether the name tag uses the default background color.
*
* @param useDefaultBackgroundColor true to use the default background color, false otherwise
* @return the builder instance
*/
Builder useDefaultBackgroundColor(boolean useDefaultBackgroundColor);
/**
* Sets the alignment of the name tag.
*
* @param alignment the alignment setting
* @return the builder instance
*/
Builder alignment(Alignment alignment);
/**
* Sets the view range for the name tag.
*
* @param viewRange the view range as a float
* @return the builder instance
*/
Builder viewRange(float viewRange);
/**
* Sets the shadow radius for the name tag.
*
* @param shadowRadius the shadow radius as a float
* @return the builder instance
*/
Builder shadowRadius(float shadowRadius);
/**
* Sets the shadow strength for the name tag.
*
* @param shadowStrength the shadow strength as a float
* @return the builder instance
*/
Builder shadowStrength(float shadowStrength);
/**
* Sets the scaling factor for the name tag.
*
* @param scale the scaling vector
* @return the builder instance
*/
Builder scale(Vector3 scale);
/**
* Sets the translation vector for the name tag.
*
* @param translation the translation vector
* @return the builder instance
*/
Builder translation(Vector3 translation);
/**
* Sets whether the name tag is affected by crouching.
*
* @param affectedByCrouching true if the name tag is affected by crouching, false otherwise
* @return the builder instance
*/
Builder affectedByCrouching(boolean affectedByCrouching);
/**
* Sets whether the name tag is affected by spectator mode.
*
* @param affectedBySpectator true if the name tag is affected by spectator mode, false otherwise
* @return the builder instance
*/
Builder affectedBySpectator(boolean affectedBySpectator);
/**
* Sets whether the name tag is affected by scaling.
*
* @param affectedByScale true if the name tag is affected by scaling, false otherwise
* @return the builder instance
*/
Builder affectedByScaling(boolean affectedByScale);
/**
* Builds and returns the configured NameTagConfig instance.
*
* @return the constructed NameTagConfig
*/
NameTagConfig build();
}
}
@@ -0,0 +1,304 @@
/*
* 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.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.Vector3;
public class NameTagConfigImpl implements NameTagConfig {
private final String id;
private final Requirement[] ownerRequirements;
private final Requirement[] viewerRequirements;
private final CarouselText[] carouselTexts;
private final int lineWidth;
private final byte opacity;
private final int backgroundColor;
private final boolean hasShadow;
private final boolean isSeeThrough;
private final boolean useDefaultBackgroundColor;
private final Alignment alignment;
private final float viewRange;
private final float shadowRadius;
private final float shadowStrength;
private final Vector3 scale;
private final Vector3 translation;
private final boolean affectedByCrouching;
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) {
this.id = id;
this.ownerRequirements = ownerRequirements;
this.viewerRequirements = viewerRequirements;
this.carouselTexts = carouselTexts;
this.opacity = opacity;
this.backgroundColor = backgroundColor;
this.hasShadow = hasShadow;
this.isSeeThrough = isSeeThrough;
this.useDefaultBackgroundColor = useDefaultBackgroundColor;
this.alignment = alignment;
this.viewRange = viewRange;
this.shadowRadius = shadowRadius;
this.shadowStrength = shadowStrength;
this.scale = scale;
this.translation = translation;
this.lineWidth = lineWidth;
this.affectedByCrouching = affectedByCrouching;
this.affectedByScale = affectedByScale;
this.affectedBySpectator = affectedBySpectator;
}
@Override
public String id() {
return id;
}
@Override
public Requirement[] ownerRequirements() {
return ownerRequirements;
}
@Override
public Requirement[] viewerRequirements() {
return viewerRequirements;
}
@Override
public CarouselText[] carouselTexts() {
return carouselTexts;
}
@Override
public byte opacity() {
return opacity;
}
@Override
public int backgroundColor() {
return backgroundColor;
}
@Override
public boolean hasShadow() {
return hasShadow;
}
@Override
public boolean isSeeThrough() {
return isSeeThrough;
}
@Override
public boolean useDefaultBackgroundColor() {
return useDefaultBackgroundColor;
}
@Override
public boolean affectedByCrouching() {
return affectedByCrouching;
}
@Override
public boolean affectedByScaling() {
return affectedByScale;
}
@Override
public boolean affectedBySpectator() {
return affectedBySpectator;
}
@Override
public Alignment alignment() {
return alignment;
}
@Override
public float viewRange() {
return viewRange;
}
@Override
public float shadowRadius() {
return shadowRadius;
}
@Override
public float shadowStrength() {
return shadowStrength;
}
@Override
public Vector3 scale() {
return scale;
}
@Override
public Vector3 translation() {
return translation;
}
@Override
public int lineWidth() {
return lineWidth;
}
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] ownerRequirements;
private Requirement[] viewerRequirements;
private CarouselText[] carouselTexts;
private int lineWidth;
private byte opacity;
private int backgroundColor;
private boolean hasShadow;
private boolean isSeeThrough;
private boolean useDefaultBackgroundColor;
private Alignment alignment;
private float viewRange;
private float shadowRadius;
private float shadowStrength;
private Vector3 scale;
private Vector3 translation;
private boolean affectedByCrouching;
private boolean affectedByScale;
private boolean affectedBySpectator;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder lineWidth(int lineWidth) {
this.lineWidth = lineWidth;
return this;
}
@Override
public Builder ownerRequirement(Requirement[] requirements) {
this.ownerRequirements = requirements;
return this;
}
@Override
public Builder viewerRequirement(Requirement[] requirements) {
this.viewerRequirements = requirements;
return this;
}
@Override
public Builder carouselText(CarouselText[] carouselTexts) {
this.carouselTexts = carouselTexts;
return this;
}
@Override
public Builder opacity(byte opacity) {
this.opacity = opacity;
return this;
}
@Override
public Builder backgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
@Override
public Builder hasShadow(boolean hasShadow) {
this.hasShadow = hasShadow;
return this;
}
@Override
public Builder seeThrough(boolean seeThrough) {
this.isSeeThrough = seeThrough;
return this;
}
@Override
public Builder useDefaultBackgroundColor(boolean useDefaultBackgroundColor) {
this.useDefaultBackgroundColor = useDefaultBackgroundColor;
return this;
}
@Override
public Builder alignment(Alignment alignment) {
this.alignment = alignment;
return this;
}
@Override
public Builder viewRange(float viewRange) {
this.viewRange = viewRange;
return this;
}
@Override
public Builder shadowRadius(float shadowRadius) {
this.shadowRadius = shadowRadius;
return this;
}
@Override
public Builder shadowStrength(float shadowStrength) {
this.shadowStrength = shadowStrength;
return this;
}
@Override
public Builder scale(Vector3 scale) {
this.scale = scale;
return this;
}
@Override
public Builder translation(Vector3 translation) {
this.translation = translation;
return this;
}
@Override
public Builder affectedByCrouching(boolean affectedByCrouching) {
this.affectedByCrouching = affectedByCrouching;
return this;
}
@Override
public Builder affectedBySpectator(boolean affectedBySpectator) {
this.affectedBySpectator = affectedBySpectator;
return this;
}
@Override
public Builder affectedByScaling(boolean affectedByScale) {
this.affectedByScale = affectedByScale;
return this;
}
@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);
}
}
}
@@ -0,0 +1,217 @@
/*
* 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.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.UUID;
public interface Tag {
/**
* Returns the ID of the tag.
*
* @return the tag ID
*/
String id();
/**
* Returns the entity ID associated with the tag.
*
* @return the entity ID
*/
int entityID();
/**
* Returns the UUID of the tag.
*
* @return the tag UUID
*/
UUID uuid();
/**
* Checks if the tag is affected by crouching.
*
* @return true if affected by crouching, false otherwise
*/
boolean affectedByCrouching();
/**
* Checks if the tag is affected by scaling.
*
* @return true if affected by scaling, false otherwise
*/
boolean affectedByScaling();
boolean affectedBySpectator();
/**
* Hides the tag for all viewers.
*/
void hide();
/**
* Hides the tag for a specific viewer.
*
* @param viewer the player for whom the tag will be hidden
*/
void hide(CNPlayer viewer);
/**
* Shows the tag to all viewers.
*/
void show();
/**
* Shows the tag to a specific viewer.
*
* @param viewer the player for whom the tag will be shown
*/
void show(CNPlayer viewer);
/**
* Respawns the tag for all viewers.
*/
void respawn();
/**
* Respawns the tag for a specific viewer.
*
* @param viewer the player for whom the tag will be respawned
*/
void respawn(CNPlayer viewer);
/**
* Returns the opacity of the tag.
*
* @return the opacity value as a byte
*/
byte opacity();
/**
* Checks if the tag can be shown to all viewers.
*
* @return true if the tag can be shown, false otherwise
*/
boolean canShow();
/**
* Checks if the tag can be shown to a specific viewer.
*
* @param viewer the player to check
* @return true if the tag can be shown, false otherwise
*/
boolean canShow(CNPlayer viewer);
/**
* Checks if the tag is currently shown to all viewers.
*
* @return true if the tag is shown, false otherwise
*/
boolean isShown();
/**
* Checks if the tag is currently shown to a specific viewer.
*
* @param viewer the player to check
* @return true if the tag is shown, false otherwise
*/
boolean isShown(CNPlayer viewer);
/**
* Called every tick to update the tag's state.
*/
void tick();
/**
* Initializes the tag.
*/
void init();
/**
* Returns the text height of the tag for a specific viewer.
*
* @param viewer the player to check
* @return the text height
*/
double getTextHeight(CNPlayer viewer);
/**
* Sets the dark mode for the tag.
*
* @param dark whether the tag should be dark
*/
void darkTag(boolean dark);
/**
* Sets the dark mode for the tag for a specific viewer.
*
* @param viewer the player for whom the dark mode should be applied
* @param dark whether the tag should be dark for the specific viewer
*/
void darkTag(CNPlayer viewer, boolean dark);
/**
* Updates the tag scale when the player's scale changes.
*
* @param scale the new scale value
*/
void onPlayerScaleUpdate(double scale);
/**
* Updates the tag scale when the player's scale changes for a specific viewer.
*
* @param viewer the player to update
* @param scale the new scale value
*/
void onPlayerScaleUpdate(CNPlayer viewer, double scale);
/**
* Updates the translation of the tag.
*/
void updateTranslation();
/**
* Updates the translation of the tag for a certain player
*/
void updateTranslation(CNPlayer viewer);
/**
* Returns the scaling vector of the tag for a specific viewer.
*
* @param viewer the player to check
* @return the scaling vector
*/
Vector3 scale(CNPlayer viewer);
/**
* Returns the translation vector of the tag for a specific viewer.
*
* @param viewer the player to check
* @return the translation vector
*/
Vector3 translation(CNPlayer viewer);
/**
* Returns if the tag has a relative translation
*
* @return has or not
*/
boolean relativeTranslation();
}
@@ -0,0 +1,92 @@
/*
* 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.api.feature.tag;
import java.util.function.Predicate;
public interface TagRenderer {
/**
* Returns the offset applied to the tag for positioning a "hat" or similar element above the entity's head.
*
* @return the hat offset value
*/
double hatOffset();
/**
* Sets the offset applied to the tag for positioning a "hat" or similar element above the entity's head.
*
* @param hatOffset the new hat offset value
*/
void hatOffset(double hatOffset);
/**
* Called every tick to update the state of the tags managed by this renderer.
*/
void onTick();
/**
* Destroys the renderer, cleaning up any resources or tags it manages.
*/
void destroy();
/**
* Adds a new tag to be rendered.
*
* @param tag the tag to add
*/
void addTag(Tag tag);
/**
* Returns the array of tags currently managed by this renderer.
*
* @return an array of Tag instances
*/
Tag[] tags();
/**
* Removes tags that match the given predicate.
*
* @param predicate a predicate to test tags for removal
* @return the number of tags removed
*/
int removeTagIf(Predicate<Tag> predicate);
/**
* Returns the index of the specified tag in the renderer's tag list.
*
* @param tag the tag to check
* @return the index of the tag, or -1 if not found
*/
int tagIndex(Tag tag);
/**
* Adds a tag at the specified index in the renderer's tag list.
*
* @param tag the tag to add
* @param index the index at which to insert the tag
*/
void addTag(Tag tag, int index);
/**
* Removes the specified tag from the renderer's tag list.
*
* @param tag the tag to remove
*/
void removeTag(Tag tag);
}
@@ -0,0 +1,50 @@
/*
* 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.api.feature.tag;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class TeamView {
private final HashMap<String, Set<String>> teamMembers = new HashMap<>();
@Nullable
public Set<String> getTeamMembers(String team) {
return teamMembers.get(team);
}
public void addTeamMembers(String team, Collection<String> members) {
teamMembers.computeIfAbsent(team, k -> new HashSet<>(members));
}
public void removeTeamMembers(String team, Collection<String> members) {
Set<String> membersSet = teamMembers.get(team);
if (membersSet != null) {
membersSet.removeAll(members);
}
}
public void removeTeam(String team) {
this.teamMembers.remove(team);
}
}
@@ -0,0 +1,133 @@
/*
* 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.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public interface UnlimitedTagManager extends Reloadable {
/**
* Called every tick to update the state of tags.
*/
void onTick();
/**
* Checks if name tags should always be shown.
*
* @return true if name tags are always shown, false otherwise
*/
boolean isAlwaysShow();
/**
* Retrieves the name tag configuration by its id.
*
* @param id the id of the tag configuration
* @return the corresponding NameTagConfig
*/
NameTagConfig configById(String id);
/**
* Returns all available name tag configurations.
*
* @return an array of all NameTagConfig instances
*/
NameTagConfig[] nameTagConfigs();
/**
* Sets whether a player is in preview mode for tags.
*
* @param player the player to update
* @param preview true to enable preview mode, false to disable
*/
void setTempPreviewing(CNPlayer player, boolean preview);
/**
* Sets whether a player can always see their tags
*
* @param player the player to update
* @param preview true to enable preview mode, false to disable
*/
void togglePreviewing(CNPlayer player, boolean preview);
/**
* Returns the duration (in ticks) for which a tag preview is shown.
*
* @return the preview duration in ticks
*/
int previewDuration();
/**
* Returns the TagRenderer responsible for rendering tags for a specific owner.
*
* @param owner the owner of the tags
* @return the TagRenderer for the owner
*/
@Nullable
TagRenderer getTagRender(CNPlayer owner);
/**
* Internal method for handling when a player is added to the owner's viewer list.
*
* @param owner the player who owns the tags
* @param added the player who is added to the viewer list
*/
@ApiStatus.Internal
void onAddPlayer(CNPlayer owner, CNPlayer added);
/**
* Internal method for handling when a player is removed from the owner's viewer list.
*
* @param owner the player who owns the tags
* @param removed the player who is removed from the viewer list
*/
@ApiStatus.Internal
void onRemovePlayer(CNPlayer owner, CNPlayer removed);
/**
* Internal method for updating a player's crouching state.
*
* @param owner the player who owns the tags
* @param viewer the player viewing the tags
* @param isCrouching true if the player is crouching, false otherwise
*/
@ApiStatus.Internal
void onPlayerDataSet(CNPlayer owner, CNPlayer viewer, boolean isCrouching);
/**
* Internal method for updating a player's scale attributes.
*
* @param owner the player who owns the tags
* @param viewer the player viewing the tags
* @param scale the new scale value
*/
@ApiStatus.Internal
void onPlayerAttributeSet(CNPlayer owner, CNPlayer viewer, double scale);
/**
* Internal method for updating a player's game mode
*
* @param owner the player who owns the tags
* @param viewer the player viewing the tags
* @param isSpectator true if the player is a spectator, false otherwise
*/
@ApiStatus.Internal
void onPlayerGameModeChange(CNPlayer owner, CNPlayer viewer, boolean isSpectator);
}
@@ -0,0 +1,339 @@
/*
* 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.api.helper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
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.momirealms.customnameplates.api.ConfigManager;
import net.momirealms.customnameplates.api.CustomNameplates;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Helper class for handling Adventure components and related functionalities.
*/
public class AdventureHelper {
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;
private final Cache<Object, String> minecraftComponentToMiniMessageCache;
private final Cache<String, String> jsonToMiniMessageCache;
private AdventureHelper() {
this.miniMessage = MiniMessage.builder().build();
this.miniMessageStrict = MiniMessage.builder().strict(true).build();
this.gsonComponentSerializer = GsonComponentSerializer.builder().build();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, r -> {
Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setName("nameplates-cache-scheduler");
return thread;
});
executor.setRemoveOnCancelPolicy(true);
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
this.miniMessageToComponentCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(1024)
.build();
this.miniMessageToMinecraftComponentCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(1024)
.build();
this.minecraftComponentToMiniMessageCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(256)
.build();
this.jsonToMiniMessageCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(256)
.build();
}
public static void clearCache() {
AdventureHelper instance = getInstance();
instance.miniMessageToMinecraftComponentCache.cleanUp();
instance.miniMessageToComponentCache.cleanUp();
instance.jsonToMiniMessageCache.cleanUp();
instance.minecraftComponentToMiniMessageCache.cleanUp();
}
private static class SingletonHolder {
private static final AdventureHelper INSTANCE = new AdventureHelper();
}
/**
* Retrieves the singleton instance of AdventureHelper.
*
* @return the singleton instance
*/
public static AdventureHelper getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* Converts a MiniMessage string to a Component.
*
* @param miniMessage the MiniMessage string
* @return the resulting Component
*/
public static Component miniMessage(String miniMessage) {
AdventureHelper instance = getInstance();
return instance.miniMessageToComponentCache.get(miniMessage, (text) -> {
if (legacySupport) {
return miniMessage().deserialize(legacyToMiniMessage(text));
} else {
return miniMessage().deserialize(text);
}
});
}
/**
* Converts a json string to a MiniMessage string.
*
* @param json the JSON string
* @return the MiniMessage string representation
*/
public static String jsonToMiniMessage(String json) {
AdventureHelper instance = getInstance();
return instance.jsonToMiniMessageCache.get(json, (rawJson) ->
instance.miniMessageStrict.serialize(instance.gsonComponentSerializer.deserialize(json))
);
}
/**
* Converts a MiniMessage string to a Minecraft component object.
*
* @param miniMessage the MiniMessage string
* @return the Minecraft component object
*/
public static Object miniMessageToMinecraftComponent(String miniMessage) {
AdventureHelper instance = getInstance();
return instance.miniMessageToMinecraftComponentCache.get(miniMessage, (text) -> {
String json = instance.gsonComponentSerializer.serialize(miniMessage(text));
return CustomNameplates.getInstance().getPlatform().jsonToMinecraftComponent(json);
});
}
/**
* Converts a MiniMessage string with a score component to a Minecraft component object.
*
* @param miniMessage the MiniMessage string
* @param name the name used in the score component
* @param objective the objective used in the score component
* @return the Minecraft component object
*/
public static Object miniMessageToMinecraftComponent(String miniMessage, String name, String objective) {
AdventureHelper instance = getInstance();
return instance.miniMessageToMinecraftComponentCache.get(miniMessage, (text) -> {
String json = instance.gsonComponentSerializer.serialize(Component.score().name(name).objective(objective).build().append(miniMessage(text)));
return CustomNameplates.getInstance().getPlatform().jsonToMinecraftComponent(json);
});
}
/**
* Converts a Minecraft component object to a MiniMessage string.
*
* @param component the Minecraft component object
* @return the MiniMessage string representation
*/
public static String minecraftComponentToMiniMessage(Object component) {
AdventureHelper instance = getInstance();
return instance.minecraftComponentToMiniMessageCache.get(component, (object) -> {
String json = CustomNameplates.getInstance().getPlatform().minecraftComponentToJson(object);
return instance.miniMessageStrict.serialize(instance.gsonComponentSerializer.deserialize(json));
});
}
/**
* Retrieves the MiniMessage instance.
*
* @return the MiniMessage instance
*/
public static MiniMessage miniMessage() {
return getInstance().miniMessage;
}
/**
* Retrieves the GsonComponentSerializer instance.
*
* @return the GsonComponentSerializer instance
*/
public static GsonComponentSerializer gson() {
return getInstance().gsonComponentSerializer;
}
/**
* Surrounds the provided text with the default nameplates font.
*
* @param text the text to surround
* @return the text surrounded by the default nameplates font tag
*/
public static String surroundWithNameplatesFont(String text) {
return surroundWithMiniMessageFont(text, ConfigManager.namespace() + ":" + ConfigManager.font());
}
/**
* Removes shadow from the provided text using a specific color code trick.
*
* @param text the text to modify
* @return the text wrapped in a color tag to remove shadows
*/
public static String removeShadowTricky(String text) {
return "<#FFFEFD>" + text + "</#FFFEFD>";
}
public static String removeShadow(String text) {
return "<#F0F0F0>" + text + "</#F0F0F0>";
}
/**
* Surrounds text with a MiniMessage font tag.
*
* @param text the text to surround
* @param font the font as a {@link Key}
* @return the text surrounded by the MiniMessage font tag
*/
public static String surroundWithMiniMessageFont(String text, Key font) {
return "<font:" + font.asString() + ">" + text + "</font>";
}
/**
* Surrounds text with a MiniMessage font tag.
*
* @param text the text to surround
* @param font the font as a {@link String}
* @return the text surrounded by the MiniMessage font tag
*/
public static String surroundWithMiniMessageFont(String text, String font) {
return "<font:" + font + ">" + text + "</font>";
}
/**
* Checks if a character is a legacy color code.
*
* @param c the character to check
* @return true if the character is a color code, false otherwise
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean isLegacyColorCode(char c) {
return c == '§' || c == '&';
}
/**
* Strips the minimessage tags
*
* @param text text
* @return the stripped texts
*/
public static String stripTags(String text) {
return getInstance().miniMessage.stripTags(text);
}
/**
* Converts a legacy color code string to a MiniMessage string.
*
* @param legacy the legacy color code string
* @return the MiniMessage string representation
*/
public static String legacyToMiniMessage(String legacy) {
StringBuilder stringBuilder = new StringBuilder();
char[] chars = legacy.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (!isLegacyColorCode(chars[i])) {
stringBuilder.append(chars[i]);
continue;
}
if (i + 1 >= chars.length) {
stringBuilder.append(chars[i]);
continue;
}
switch (chars[i+1]) {
case '0' -> stringBuilder.append("<black>");
case '1' -> stringBuilder.append("<dark_blue>");
case '2' -> stringBuilder.append("<dark_green>");
case '3' -> stringBuilder.append("<dark_aqua>");
case '4' -> stringBuilder.append("<dark_red>");
case '5' -> stringBuilder.append("<dark_purple>");
case '6' -> stringBuilder.append("<gold>");
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' -> {
if (i + 13 >= chars.length
|| !isLegacyColorCode(chars[i+2])
|| !isLegacyColorCode(chars[i+4])
|| !isLegacyColorCode(chars[i+6])
|| !isLegacyColorCode(chars[i+8])
|| !isLegacyColorCode(chars[i+10])
|| !isLegacyColorCode(chars[i+12])) {
stringBuilder.append(chars[i]);
continue;
}
stringBuilder
.append("<#")
.append(chars[i+3])
.append(chars[i+5])
.append(chars[i+7])
.append(chars[i+9])
.append(chars[i+11])
.append(chars[i+13])
.append(">");
i += 12;
}
default -> {
stringBuilder.append(chars[i]);
continue;
}
}
i++;
}
return stringBuilder.toString();
}
}
@@ -0,0 +1,59 @@
/*
* 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.api.helper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Helper class for managing Gson instances.
*/
public class GsonHelper {
private final Gson gson;
public GsonHelper() {
this.gson = new GsonBuilder()
.create();
}
/**
* Retrieves the Gson instance.
*
* @return the Gson instance
*/
public Gson getGson() {
return gson;
}
/**
* Retrieves the singleton Gson instance from GsonHelper.
*
* @return the singleton Gson instance
*/
public static Gson get() {
return SingletonHolder.INSTANCE.getGson();
}
/**
* Static inner class for holding the singleton instance of GsonHelper.
*/
private static class SingletonHolder {
private static final GsonHelper INSTANCE = new GsonHelper();
}
}
@@ -0,0 +1,170 @@
/*
* 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.api.helper;
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* This class implements the VersionManager interface and is responsible for managing version-related information.
*/
public class VersionHelper {
// Method to asynchronously check for plugin updates
public static final Function<NameplatesPlugin, CompletableFuture<Boolean>> UPDATE_CHECKER = (plugin) -> {
CompletableFuture<Boolean> updateFuture = new CompletableFuture<>();
plugin.getScheduler().async().execute(() -> {
try {
URL url = new URL("https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=2723&key=version");
URLConnection conn = url.openConnection();
conn.setConnectTimeout(10000);
conn.setReadTimeout(60000);
InputStream inputStream = conn.getInputStream();
String newest = new BufferedReader(new InputStreamReader(inputStream)).readLine();
String current = plugin.getPluginVersion();
inputStream.close();
if (!compareVer(newest, current)) {
updateFuture.complete(false);
return;
}
updateFuture.complete(true);
} catch (Exception exception) {
plugin.getPluginLogger().warn("Error occurred when checking update.");
updateFuture.completeExceptionally(exception);
}
});
return updateFuture;
};
private static float version;
private static boolean mojmap;
private static boolean folia;
public static void init(String serverVersion) {
String[] split = serverVersion.split("\\.");
version = Float.parseFloat(split[1] + "." + (split.length == 3 ? split[2] : "0"));
checkMojMap();
checkFolia();
}
public static float version() {
return version;
}
private static void checkMojMap() {
// Check if the server is Mojmap
try {
Class.forName("net.minecraft.network.protocol.game.ClientboundBossEventPacket");
mojmap = true;
} catch (ClassNotFoundException ignored) {
}
}
private static void checkFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
folia = true;
} catch (ClassNotFoundException ignored) {
}
}
public static boolean isVersionNewerThan1_21_2() {
return version >= 21.19;
}
public static boolean isVersionNewerThan1_20_5() {
return version >= 20.49;
}
public static boolean isVersionNewerThan1_20_4() {
return version >= 20.39;
}
public static boolean isVersionNewerThan1_19_4() {
return version >= 19.39;
}
public static boolean isVersionNewerThan1_20_2() {
return version >= 20.19;
}
public static boolean isVersionNewerThan1_20() {
return version >= 20;
}
public static boolean isFolia() {
return folia;
}
public static boolean isMojmap() {
return mojmap;
}
// Method to compare two version strings
private static boolean compareVer(String newV, String currentV) {
if (newV == null || currentV == null || newV.isEmpty() || currentV.isEmpty()) {
return false;
}
String[] newVS = newV.split("\\.");
String[] currentVS = currentV.split("\\.");
int maxL = Math.min(newVS.length, currentVS.length);
for (int i = 0; i < maxL; i++) {
try {
String[] newPart = newVS[i].split("-");
String[] currentPart = currentVS[i].split("-");
int newNum = Integer.parseInt(newPart[0]);
int currentNum = Integer.parseInt(currentPart[0]);
if (newNum > currentNum) {
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;
}
}
return newVS.length > currentVS.length;
}
}
@@ -1,191 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public interface AdventureManager {
/**
* Strip all the tags from text
*
* @param text text
* @return stripped
*/
String stripTags(String text);
/**
* Get component from text
*
* @param text text
* @return component
*/
Component getComponentFromMiniMessage(String text);
/**
* Send a message to a command sender
*
* @param sender sender
* @param msg message
*/
void sendMessage(CommandSender sender, String msg);
/**
* Send a message with prefix to a command sender
*
* @param sender sender
* @param msg message
*/
void sendMessageWithPrefix(CommandSender sender, String msg);
/**
* Send a message to console
*
* @param msg message
*/
void sendConsoleMessage(String msg);
/**
* Send a message to a player
*
* @param player player
* @param msg message
*/
void sendPlayerMessage(Player player, String msg);
/**
* Send a title
*
* @param player player
* @param title title
* @param subtitle subtitle
* @param in in (ms)
* @param duration duration (ms)
* @param out out (ms)
*/
void sendTitle(Player player, String title, String subtitle, int in, int duration, int out);
/**
* Send a title
*
* @param player player
* @param title title
* @param subtitle subtitle
* @param in in (ms)
* @param duration duration (ms)
* @param out out (ms)
*/
void sendTitle(Player player, Component title, Component subtitle, int in, int duration, int out);
/**
* Send an actionbar
*
* @param player player
* @param msg msg
*/
void sendActionbar(Player player, String msg);
/**
* Send an actionbar
*
* @param player player
* @param component component
*/
void sendActionbar(Player player, Component component);
/**
* Play a sound to a player
*
* @param player player
* @param source sound source
* @param key sound key
* @param volume volume
* @param pitch pitch
*/
void sendSound(Player player, Sound.Source source, Key key, float volume, float pitch);
/**
* Play a sound to a player
*
* @param player player
* @param sound sound
*/
void sendSound(Player player, Sound sound);
/**
* Replace legacy color codes to MiniMessage format
*
* @param legacy legacy text
* @return MiniMessage format text
*/
String legacyToMiniMessage(String legacy);
/**
* If a char is legacy color code
*
* @param c char
* @return is legacy color
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isColorCode(char c);
/**
* Convert a color into decimal
*
* @param color color
* @return decimal
*/
int colorToDecimal(ChatColor color);
/**
* Get legacy format text
*
* @param component component
* @return legacy format text
*/
String componentToLegacy(Component component);
/**
* Get json by component
*
* @param component component
* @return json
*/
String componentToJson(Component component);
/**
* Get MiniMessage format text from component
*
* @param component component
* @return text
*/
String getMiniMessageFormat(Component component);
/**
* Get IChatComponent from Json
*
* @param json json
* @return component
*/
Object getIChatComponent(String json);
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.background.BackGround;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface BackGroundManager {
/**
* Get a background's config by key
*
* @param key key
* @return background
*/
@Nullable
BackGround getBackGround(@NotNull String key);
/**
* Get all the backgrounds
*
* @return backgrounds
*/
Collection<BackGround> getBackGrounds();
/**
* Register a background into the plugin
* This will fail if there already exists one with the same key
*
* @param key key
* @param backGround background
* @return success or not
*/
boolean registerBackGround(@NotNull String key, @NotNull BackGround backGround);
/**
* Unregister a background by key
* This will fail if the key doesn't exist
*
* @param key key
* @return success or not
*/
boolean unregisterBackGround(@NotNull String key);
}
@@ -1,135 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.bubble.Bubble;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
public interface BubbleManager {
/**
* Register a bubble into map
*
* @param key key
* @param bubble bubble
* @return success or not
*/
boolean registerBubble(String key, Bubble bubble);
/**
* Unregister a bubble from map
*
* @param key key
* @return success or not
*/
boolean unregisterBubble(String key);
/**
* Get a bubble from map
*
* @param bubble key
* @return bubble
*/
@Nullable Bubble getBubble(String bubble);
/**
* If a player has a certain bubble
*
* @param player player
* @param bubble key
* @return
*/
boolean hasBubble(Player player, String bubble);
/**
* Get a list of the bubbles that a player has
*
* @param player player
* @return bubbles' keys
*/
List<String> getAvailableBubbles(Player player);
/**
* Get a list of the bubbles' display names that a player has
*
* @param player player
* @return bubbles' display names
*/
List<String> getAvailableBubblesDisplayNames(Player player);
/**
* Get blacklist chat channels
*
* @return channels
*/
String[] getBlacklistChannels();
/**
* Get all the bubbles
*
* @return bubbles
*/
Collection<Bubble> getBubbles();
/**
* Whether a bubble exists
*/
boolean containsBubble(String key);
/**
* Equip a bubble for a player
*
* @param player player
* @param bubble bubble
* @return success or not
*/
boolean equipBubble(Player player, String bubble);
/**
* Unequip a bubble for a player
*
* @param player player
*/
void unEquipBubble(Player player);
/**
* Get the default bubble key
*
* @return bubble key
*/
String getDefaultBubble();
/**
* Get all the bubbles' keys
*
* @return keys
*/
Collection<String> getBubbleKeys();
/**
* Trigger chat
*
* @param player player
* @param text text
*/
void onChat(Player player, String text);
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface ImageManager {
/**
* Get an image by key
*
* @param key key
* @return image
*/
@Nullable
ConfiguredChar getImage(@NotNull String key);
/**
* Get all the images
*
* @return images
*/
Collection<ConfiguredChar> getImages();
/**
* Register am image into the plugin
* This will fail if there already exists one with the same key
*
* @param key key
* @param configuredChar image
* @return success or not
*/
boolean registerImage(@NotNull String key, @NotNull ConfiguredChar configuredChar);
/**
* Unregister an image by key
* This will fail if the key doesn't exist
*
* @param key key
* @return success or not
*/
boolean unregisterImage(@NotNull String key);
}
@@ -1,311 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.nameplate.CachedNameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.TagMode;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.common.team.TeamColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
public interface NameplateManager {
/**
* Get the default nameplate
*/
@NotNull
String getDefaultNameplate();
/**
* Put an entity's ID to map
* This map is used for quickly getting the entity instance
* Removal from the map is necessary when the entity is invalid
* Otherwise it would cause memory leak
*
* @param entityID entityID
* @param entity entity
*/
boolean putEntityIDToMap(int entityID, @NotNull Entity entity);
/**
* Remove the entity from map
*
* @param entityID entityID
* @return the removed entity
*/
@Nullable
Entity removeEntityIDFromMap(int entityID);
/**
* Nameplates are cached in memory so they would not be frequently updated
* The update rate is decided by "refresh-frequency" in nameplate.yml
*
* @param uuid player uuid
* @param nameplate cached nameplate
*/
boolean putCachedNameplateToMap(@NotNull UUID uuid, @NotNull CachedNameplate nameplate);
/**
* Remove CachedNameplate from map
*
* @param uuid player uuid
* @return removed CachedNameplate
*/
@Nullable
CachedNameplate removeCachedNameplateFromMap(@NotNull UUID uuid);
/**
* Get player by entityID from the cache
*
* @param id entityID
* @return player
*/
@Nullable
Player getPlayerByEntityID(int id);
/**
* Get entity by entityID from the cache
*
* @param id entityID
* @return entity
*/
@Nullable
Entity getEntityByEntityID(int id);
/**
* Update a player's cached nameplate
* The nameplate is affected by "prefix" and "suffix" option
*
* @param player player
* @return if the nameplate is updated
*/
boolean updateCachedNameplate(@NotNull Player player);
/**
* Update a player's cached nameplate
* The nameplate is affected by "prefix" and "suffix" option
*
* @param player player
* @return if the nameplate is updated
*/
boolean updateCachedNameplate(@NotNull Player player, @Nullable Nameplate nameplate);
/**
* This should not be null when player's data is loaded (async process)
*
* @param player player
* @return cached nameplate
*/
@Nullable
CachedNameplate getCacheNameplate(@NotNull Player player);
/**
* Create a name tag for a player, the tag type is decided by the mode in nameplate.yml
* If mode is DISABLE, this method would return null
* The tag would be put into map automatically and you can get it by getNameplatePlayer(uuid)
*
* @param player player
*/
@Nullable
NameplatePlayer createNameTag(@NotNull Player player);
/**
* Put a nameplater player to map
*
* @param player player
*/
void putNameplatePlayerToMap(@NotNull NameplatePlayer player);
/**
* Get a nameplate player from map
*
* @param uuid uuid
* @return nameplate player
*/
@Nullable
NameplatePlayer getNameplatePlayer(@NotNull UUID uuid);
/**
* Remove nameplate player from map
*
* @param uuid uuid
* @return removed nameplate player
*/
@Nullable
NameplatePlayer removeNameplatePlayerFromMap(@NotNull UUID uuid);
/**
* Get the nameplate's prefix with text tags
*
* @param player player
* @return prefix with text tags
*/
@NotNull
String getNameplatePrefix(@NotNull Player player);
/**
* Get the nameplate's suffix with text tags
*
* @param player player
* @return suffix with text tags
*/
@NotNull
String getNameplateSuffix(@NotNull Player player);
/**
* Get the full nameplate tag
*
* @param player player
* @return nameplate tag
*/
@NotNull
String getFullNameTag(@NotNull Player player);
/**
* Register a custom nameplate into map
*
* @param key key
* @param nameplate nameplate
* @return success or not
*/
boolean registerNameplate(@NotNull String key, @NotNull Nameplate nameplate);
/**
* Unregister a nameplate from map
*
* @param key key
* @return success or not
*/
boolean unregisterNameplate(@NotNull String key);
/**
* Equip a nameplate for a player
*
* @param player player
* @param nameplateKey key
* @param temp whether save to storage
* @return success or not
*/
boolean equipNameplate(@NotNull Player player, @NotNull String nameplateKey, boolean temp);
/**
* Remove a nameplate for a player
*
* @param player player
* @param temp whether save to storage
*/
void unEquipNameplate(Player player, boolean temp);
/**
* Is team managed on proxy side
*/
boolean isProxyMode();
/**
* Get preview duration
*/
int getPreviewDuration();
/**
* Get the tag mode
*/
@NotNull
TagMode getTagMode();
/**
* Get a nameplate by key
*
* @param key key
* @return nameplate
*/
@NotNull
Nameplate getNameplate(@NotNull String key);
/**
* Get all the nameplates
*
* @return nameplates
*/
@NotNull
Collection<Nameplate> getNameplates();
/**
* Get all the nameplates' keys
*
* @return keys
*/
@NotNull
Collection<String> getNameplateKeys();
/**
* Whether a nameplate key exists
*/
boolean containsNameplate(@NotNull String key);
/**
* Get all the nameplates that the player has
*
* @param player player
* @return nameplates' keys
*/
@NotNull
List<String> getAvailableNameplates(@NotNull Player player);
/**
* If player has permission for a certain nameplate
*/
boolean hasNameplate(@NotNull Player player, @NotNull String nameplate);
/**
* Get all the nameplates' display names that the player has
*
* @param player player
* @return nameplates' display names
*/
@NotNull
List<String> getAvailableNameplateDisplayNames(@NotNull Player player);
/**
* Get the nameplate's team color
*
* @param player player
* @return team color
*/
@NotNull
TeamColor getTeamColor(@NotNull Player player);
/**
* Get team tag manager
*/
@NotNull
TeamTagManager getTeamTagManager();
/**
* Get unlimited tag manager
*/
@NotNull
UnlimitedTagManager getUnlimitedTagManager();
}
@@ -1,148 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.placeholder.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
public interface PlaceholderManager {
/**
* Detect all the placeholders
*
* @param text text
* @return placeholder
*/
@NotNull
List<String> detectPlaceholders(String text);
/**
* Get a static text instance
*
* @param key key
* @return static text
*/
@Nullable
StaticText getStaticText(String key);
/**
* Get all the static texts
*
* @return static texts
*/
Collection<StaticText> getStaticTexts();
/**
* Get a switch text instance
*
* @param key key
* @return switch text
*/
@Nullable
SwitchText getSwitchText(String key);
/**
* Get all the switch texts
*
* @return switch texts
*/
Collection<SwitchText> getSwitchTexts();
/**
* Get a descent text instance
*
* @param key key
* @return descent text
*/
@Nullable
DescentText getDescentText(String key);
/**
* Get all the descent texts
*
* @return descent texts
*/
Collection<DescentText> getDescentTexts();
/**
* Get a conditional text
*
* @param key key
* @return conditional text
*/
@Nullable
ConditionalText getConditionalText(String key);
/**
* Get all the conditional texts
*
* @return conditional texts
*/
Collection<ConditionalText> getConditionalTexts();
/**
* Get a nameplate text
*
* @param key key
* @return nameplate text
*/
@Nullable
NameplateText getNameplateText(String key);
/**
* Get all the nameplate texts
*
* @return nameplate texts
*/
Collection<NameplateText> getNameplateTexts();
/**
* Get a background text
*
* @param key key
* @return background text
*/
@Nullable
BackGroundText getBackGroundText(String key);
/**
* Get all the background texts
*
* @return background texts
*/
Collection<BackGroundText> getBackGroundTexts();
/**
* Get a vanilla hud
*
* @param key key
* @return vanilla hud
*/
VanillaHud getVanillaHud(String key);
/**
* Get all the vanilla huds
*
* @return vanilla huds
*/
Collection<VanillaHud> getVanillaHuds();
}
@@ -1,104 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.requirement.RequirementFactory;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface RequirementManager {
/**
* Registers a custom requirement type with its corresponding factory.
*
* @param type The type identifier of the requirement.
* @param requirementFactory The factory responsible for creating instances of the requirement.
* @return True if registration was successful, false if the type is already registered.
*/
boolean registerRequirement(String type, RequirementFactory requirementFactory);
/**
* Unregisters a custom requirement type.
*
* @param type The type identifier of the requirement to unregister.
* @return True if unregistration was successful, false if the type is not registered.
*/
boolean unregisterRequirement(String type);
/**
* Retrieves an array of requirements based on a configuration section.
*
* @param section The configuration section containing requirement definitions.
* @return An array of Requirement objects based on the configuration section
*/
@Nullable Requirement[] getRequirements(ConfigurationSection section);
/**
* Retrieves a Requirement object based on a configuration section and advanced flag.
* <p>
* requirement_1: <- section
* type: xxx
* value: xxx
*
* @param section The configuration section containing requirement definitions.
* @return A Requirement object based on the configuration section, or an EmptyRequirement if the section is null or invalid.
*/
@NotNull Requirement getRequirement(ConfigurationSection section);
/**
* Gets a requirement based on the provided type and value.
* If a valid RequirementFactory is found for the type, it is used to create the requirement.
* If no factory is found, a warning is logged, and an empty requirement instance is returned.
* <p>
* world: <- type
* - world <- value
*
* @param type The type representing the requirement type.
* @param value The value associated with the requirement.
* @return A Requirement instance based on the type and value, or an EmptyRequirement if the type is invalid.
*/
@NotNull Requirement getRequirement(String type, Object value);
/**
* Retrieves a RequirementFactory based on the specified requirement type.
*
* @param type The requirement type for which to retrieve a factory.
* @return A RequirementFactory for the specified type, or null if no factory is found.
*/
@Nullable RequirementFactory getRequirementFactory(String type);
/**
* Checks if an array of requirements is met for a given condition.
*
* @param condition The Condition object to check against the requirements.
* @param requirements An array of Requirement instances to be evaluated.
* @return True if all requirements are met, false otherwise. Returns true if the requirements array is null.
*/
static boolean isRequirementMet(Condition condition, Requirement... requirements) {
if (requirements == null) return true;
for (Requirement requirement : requirements) {
if (!requirement.isConditionMet(condition)) {
return false;
}
}
return true;
}
}
@@ -1,108 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.data.DataStorageInterface;
import net.momirealms.customnameplates.api.data.OnlineUser;
import net.momirealms.customnameplates.api.data.PlayerData;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface StorageManager {
/**
* Get online users
*
* @return online users
*/
Collection<OnlineUser> getOnlineUsers();
/**
* Get a player's data by uuid
* The player can be an offline one
*
* @param uuid uuid
* @return player data
*/
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid);
/**
* Save online players' data
*
* @param uuid uuid
* @return success or not
*/
CompletableFuture<Boolean> saveOnlinePlayerData(UUID uuid);
/**
* Save specified data
*
* @param uuid uuid
* @param playerData playerData
* @return success or not
*/
CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData);
/**
* Get an online user by uuid
*
* @param uuid uuid
* @return online user
*/
Optional<OnlineUser> getOnlineUser(UUID uuid);
/**
* Get player data from json
*
* @param json json
* @return data
*/
@NotNull
PlayerData fromJson(String json);
/**
* Get player data from bytes
*
* @param data data
* @return data
*/
PlayerData fromBytes(byte[] data);
/**
* Convert player data to bytes
*
* @param playerData playerData
* @return bytes
*/
byte[] toBytes(PlayerData playerData);
/**
* Convert player data to json
*
* @param playerData playerData
* @return json
*/
@NotNull
String toJson(@NotNull PlayerData playerData);
DataStorageInterface getDataSource();
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.common.team.TeamColor;
import net.momirealms.customnameplates.common.team.TeamTagVisibility;
import org.bukkit.entity.Player;
public interface TeamManager {
/**
* Create team for a player
*
* @param player player
*/
void createTeam(Player player);
/**
* Remove a team for a player
*
* @param player player
*/
void removeTeam(Player player);
/**
* Update a player's team for a viewer
*/
void updateTeam(Player owner, Player viewer, String prefix, String suffix, TeamColor color, TeamTagVisibility visibility);
/**
* Get the team player in
*
* @param player player
* @param viewer viewer
* @return team name
*/
String getTeamName(Player player, Player viewer);
}
@@ -1,63 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public interface UnlimitedTagManager {
/**
* Create a named entity (ArmorStand) for an entity
* To apply the changes, you should add it to the EntityTagEntity
*
* @param entity entity
* @param setting setting
* @return named entity
*/
@NotNull StaticTextEntity createNamedEntity(EntityTagEntity entity, StaticTextTagSetting setting);
/**
* Create a named entity (ArmorStand) for a player
* To apply the changes, you should add it the named player instance
*
* @param player player
* @param setting setting
* @return named entity
*/
@NotNull
DynamicTextEntity createNamedEntity(EntityTagPlayer player, DynamicTextTagSetting setting);
/**
* Create or get a tag instance
*
* @param entity entity
* @return entity tag instance
*/
EntityTagEntity createOrGetTagForEntity(Entity entity);
/**
* Create or get a tag instance
*
* @param player player
* @return entity tag instance
*/
EntityTagPlayer createOrGetTagForPlayer(Player player);
}
@@ -1,76 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletionStage;
public interface VersionManager {
/**
* Is folia scheduler implemented
*/
boolean isFolia();
/**
* Get bukkit version
*
* @return version
*/
String getServerVersion();
/**
* Check update
*
* @return return true if plugin needs update
*/
CompletionStage<Boolean> checkUpdate();
/**
* Get plugin version
*
* @return version
*/
@NotNull
String getPluginVersion();
/**
* Is the plugin the latest version
*
* @return latest or not
*/
boolean isLatest();
/**
* Get pack format
*
* @return pack format
*/
int getPackFormat();
boolean isVersionNewerThan1_19();
boolean isVersionNewerThan1_19_R2();
boolean isVersionNewerThan1_19_R3();
boolean isVersionNewerThan1_20();
boolean isVersionNewerThan1_20_R2();
}
@@ -1,61 +0,0 @@
/*
* Copyright (C) <2022> <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.api.manager;
import net.momirealms.customnameplates.api.mechanic.font.FontData;
import net.momirealms.customnameplates.common.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface WidthManager {
/**
* Register a font data into the plugin
* If there already exists one, it would fail
*
* @param key key
* @param fontData data
* @return success or not
*/
boolean registerFontData(@NotNull Key key, @NotNull FontData fontData);
/**
* Unregister a font data from map
*
* @param key key
* @return success or not
*/
boolean unregisterFontData(@NotNull Key key);
/**
* Get font data by key
*
* @param key key
* @return font data
*/
@Nullable
FontData getFontData(@NotNull Key key);
/**
* Get text's width (MiniMessage format text)
*
* @param textWithTags text
* @return width
*/
int getTextWidth(@NotNull String textWithTags);
}
@@ -1,230 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.background;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
public class BackGround {
private ConfiguredChar left, offset_1, offset_2, offset_4, offset_8, offset_16, offset_32, offset_64, offset_128, right;
private int leftMargin, rightMargin;
private BackGround() {
}
public BackGround(
ConfiguredChar left,
ConfiguredChar offset_1,
ConfiguredChar offset_2,
ConfiguredChar offset_4,
ConfiguredChar offset_8,
ConfiguredChar offset_16,
ConfiguredChar offset_32,
ConfiguredChar offset_64,
ConfiguredChar offset_128,
ConfiguredChar right,
int leftMargin,
int rightMargin,
boolean removeShadow
) {
this.left = left;
this.offset_1 = offset_1;
this.offset_2 = offset_2;
this.offset_4 = offset_4;
this.offset_8 = offset_8;
this.offset_16 = offset_16;
this.offset_32 = offset_32;
this.offset_64 = offset_64;
this.offset_128 = offset_128;
this.right = right;
this.leftMargin = leftMargin;
this.rightMargin = rightMargin;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getOffset_1() {
return offset_1;
}
public ConfiguredChar getOffset_2() {
return offset_2;
}
public ConfiguredChar getOffset_4() {
return offset_4;
}
public ConfiguredChar getOffset_8() {
return offset_8;
}
public ConfiguredChar getOffset_16() {
return offset_16;
}
public ConfiguredChar getOffset_32() {
return offset_32;
}
public ConfiguredChar getOffset_64() {
return offset_64;
}
public ConfiguredChar getOffset_128() {
return offset_128;
}
public ConfiguredChar getRight() {
return right;
}
public static Builder builder() {
return new Builder();
}
public String getBackGroundImage(int n) {
String offset = OffsetFont.getShortestNegChars(n + rightMargin + 2);
n = n + leftMargin + rightMargin + 2;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.getCharacter());
while (n >= 128) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_8.getCharacter());
n -= 8;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_4.getCharacter());
n -= 4;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_1.getCharacter());
}
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(right.getCharacter());
stringBuilder.append(offset);
return stringBuilder.toString();
}
public static class Builder {
private final BackGround backGround;
public static Builder of() {
return new Builder();
}
public Builder() {
this.backGround = new BackGround();
}
public Builder left(ConfiguredChar configuredChar) {
backGround.left = configuredChar;
return this;
}
public Builder right(ConfiguredChar configuredChar) {
backGround.right = configuredChar;
return this;
}
public Builder offset_1(ConfiguredChar configuredChar) {
backGround.offset_1 = configuredChar;
return this;
}
public Builder offset_2(ConfiguredChar configuredChar) {
backGround.offset_2 = configuredChar;
return this;
}
public Builder offset_4(ConfiguredChar configuredChar) {
backGround.offset_4 = configuredChar;
return this;
}
public Builder offset_8(ConfiguredChar configuredChar) {
backGround.offset_8 = configuredChar;
return this;
}
public Builder offset_16(ConfiguredChar configuredChar) {
backGround.offset_16 = configuredChar;
return this;
}
public Builder offset_32(ConfiguredChar configuredChar) {
backGround.offset_32 = configuredChar;
return this;
}
public Builder offset_64(ConfiguredChar configuredChar) {
backGround.offset_64 = configuredChar;
return this;
}
public Builder offset_128(ConfiguredChar configuredChar) {
backGround.offset_128 = configuredChar;
return this;
}
public Builder leftMargin(int margin) {
backGround.leftMargin = margin;
return this;
}
public Builder rightMargin(int margin) {
backGround.rightMargin = margin;
return this;
}
public BackGround build() {
return backGround;
}
}
}
@@ -1,172 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.bubble;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.util.FontUtils;
public class Bubble {
private String startFormat, endFormat;
private String displayName;
private ConfiguredChar left, middle, right, tail;
private Bubble() {
}
public Bubble(String startFormat, String endFormat, String displayName, ConfiguredChar left, ConfiguredChar middle, ConfiguredChar right, ConfiguredChar tail) {
this.startFormat = startFormat;
this.endFormat = endFormat;
this.displayName = displayName;
this.left = left;
this.middle = middle;
this.right = right;
this.tail = tail;
}
public String getPrefixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getPrefix(textWidth));
}
public String getPrefix(int textWidth) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<#FEFEFE>");
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + left.getWidth() + 1));
stringBuilder.append(left.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
int mid_amount;
if (textWidth - 1 <= tail.getWidth()) {
mid_amount = -1;
} else {
mid_amount = (textWidth - 1 - tail.getWidth()) / (middle.getWidth());
}
if (mid_amount == -1) {
stringBuilder.append("<#FDFEFE>").append(tail.getCharacter()).append("</#FDFEFE>").append(OffsetFont.NEG_1.getCharacter());
} else if (mid_amount == 0) {
stringBuilder.append("<#FDFEFE>").append(tail.getCharacter()).append("</#FDFEFE>").append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - (textWidth - 1 - tail.getWidth()) % middle.getWidth()));
stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
} else {
stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
for (int i = 0; i < mid_amount; i++) {
if (i == mid_amount / 2) stringBuilder.append("<#FDFEFE>").append(tail.getCharacter()).append("</#FDFEFE>").append(OffsetFont.NEG_1.getCharacter());
else stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - (textWidth - 1 - tail.getWidth()) % middle.getWidth()));
stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append("<#FDFEFE>");
stringBuilder.append(right.getCharacter());
stringBuilder.append("</#FDFEFE>");
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + right.getWidth()));
stringBuilder.append("</#FEFEFE>");
return stringBuilder.toString();
}
public String getSuffixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getSuffix(textWidth));
}
public String getSuffix(int textWidth) {
return OffsetFont.getShortestNegChars(textWidth + textWidth % 2 + 1);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final Bubble bubble;
public static Builder of() {
return new Builder();
}
public Builder() {
this.bubble = new Bubble();
}
public Builder startFormat(String startFormat) {
this.bubble.startFormat = startFormat;
return this;
}
public Builder endFormat(String endFormat) {
this.bubble.endFormat = endFormat;
return this;
}
public Builder left(ConfiguredChar left) {
this.bubble.left = left;
return this;
}
public Builder displayName(String displayName) {
this.bubble.displayName = displayName;
return this;
}
public Builder middle(ConfiguredChar middle) {
this.bubble.middle = middle;
return this;
}
public Builder right(ConfiguredChar right) {
this.bubble.right = right;
return this;
}
public Builder tail(ConfiguredChar tail) {
this.bubble.tail = tail;
return this;
}
public Bubble build() {
return bubble;
}
}
public String getStartFormat() {
return startFormat;
}
public String getEndFormat() {
return endFormat;
}
public String getDisplayName() {
return displayName;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getMiddle() {
return middle;
}
public ConfiguredChar getRight() {
return right;
}
public ConfiguredChar getTail() {
return tail;
}
}
@@ -1,124 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.character;
import net.momirealms.customnameplates.api.util.LogUtils;
public class ConfiguredChar {
private char character;
private String pngFile;
private int height;
private int width;
private int ascent;
private ConfiguredChar() {
}
public ConfiguredChar(char character, String pngFile, int height, int width, int ascent) {
this.character = character;
this.pngFile = pngFile;
this.height = height;
this.width = width;
this.ascent = ascent;
}
public char getCharacter() {
return character;
}
public static Builder builder() {
return new Builder();
}
public String getPngFile() {
return pngFile;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getAscent() {
return ascent;
}
public String getFile() {
return pngFile + ".png";
}
public static class Builder {
private final ConfiguredChar configuredChar;
public static Builder of() {
return new Builder();
}
public Builder() {
this.configuredChar = new ConfiguredChar();
}
public Builder character(char character) {
configuredChar.character = character;
return this;
}
public Builder png(String png) {
configuredChar.pngFile = png;
return this;
}
public Builder height(int height) {
configuredChar.height = height;
return this;
}
public Builder ascent(int ascent) {
configuredChar.ascent = ascent;
if (ascent >= configuredChar.height) {
LogUtils.warn("Invalid config for " + configuredChar.pngFile);
LogUtils.warn("Ascent " + ascent + " should be no higher than Height " + configuredChar.height);
}
return this;
}
public Builder descent(int descent) {
if (descent < 0) {
LogUtils.warn("Invalid config for " + configuredChar.pngFile);
LogUtils.warn("Descent " + descent + " should be no lower than 0");
}
configuredChar.ascent = configuredChar.height - descent;
return this;
}
public Builder width(int width) {
configuredChar.width = width;
return this;
}
public ConfiguredChar build() {
return configuredChar;
}
}
}
@@ -1,78 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.font;
import java.util.HashMap;
public class FontData {
private final HashMap<Integer, Integer> widthData;
private final int defaultWidth;
public FontData(int defaultWidth) {
this.widthData = new HashMap<>();
this.defaultWidth = defaultWidth;
}
/**
* Register a char's width
*
* @param codePoint code point
* @param width width
*/
public void registerCharWidth(int codePoint, int width) {
widthData.put(codePoint, width);
}
/**
* Get a character's width
*
* @param codePoint code point
* @return width
*/
public int getWidth(int codePoint) {
return widthData.getOrDefault(codePoint, defaultWidth);
}
/**
* Get the data map
*
* @return map
*/
public HashMap<Integer, Integer> getWidthData() {
return widthData;
}
/**
* Override the data with another one
*
* @param fontData font data
*/
public void overrideWith(FontData fontData) {
if (fontData == null) return;
widthData.putAll(fontData.getWidthData());
}
@Override
public String toString() {
return "FontData{" +
"widthData=" + widthData +
", defaultWidth=" + defaultWidth +
'}';
}
}
@@ -1,198 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.font;
public enum OffsetFont {
NEG_1('\uf801', -1, -3),
NEG_2('\uf802', -2, -4),
NEG_3('\uf803', -3, -5),
NEG_4('\uf804', -4, -6),
NEG_5('\uf805', -5, -7),
NEG_6('\uf806', -6, -8),
NEG_7('\uf807', -7, -9),
NEG_8('\uf808', -8, -10),
NEG_16('\uf809', -16, -18),
NEG_32('\uf80a', -32, -34),
NEG_64('\uf80b', -64, -66),
NEG_128('\uf80c', -128, -130),
POS_1('\uf811', 1, -1),
POS_2('\uf812', 2, 1),
POS_3('\uf813', 3, 2),
POS_4('\uf814', 4, 3),
POS_5('\uf815', 5, 4),
POS_6('\uf816', 6, 5),
POS_7('\uf817', 7, 6),
POS_8('\uf818', 8, 7),
POS_16('\uf819', 16, 15),
POS_32('\uf81a', 32, 31),
POS_64('\uf81b', 64, 63),
POS_128('\uf81c', 128, 127);
private final char character;
private final int space;
private final int height;
OffsetFont(char character, int space, int height) {
this.character = character;
this.space = space;
this.height = height;
}
public char getCharacter() {
return this.character;
}
public int getSpace() {
return this.space;
}
public int getHeight() {
return this.height;
}
/**
* Get offset characters
*
* @param offset offset
* @return chars
*/
public static String getOffsetChars(int offset) {
if (offset >= 0) {
return getShortestPosChars(offset);
} else {
return getShortestNegChars(-offset);
}
}
/**
* get negative characters
*
* @param n n > 0
* @return chars
*/
public static String getShortestNegChars(int n) {
StringBuilder stringBuilder = new StringBuilder();
while (n >= 128) {
stringBuilder.append(OffsetFont.NEG_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_8.getCharacter());
n -= 8;
}
if (n - 7 >= 0) {
stringBuilder.append(OffsetFont.NEG_7.getCharacter());
n -= 7;
}
if (n - 6 >= 0) {
stringBuilder.append(OffsetFont.NEG_6.getCharacter());
n -= 6;
}
if (n - 5 >= 0) {
stringBuilder.append(OffsetFont.NEG_5.getCharacter());
n -= 5;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_4.getCharacter());
n -= 4;
}
if (n - 3 >= 0) {
stringBuilder.append(OffsetFont.NEG_3.getCharacter());
n -= 3;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
}
return stringBuilder.toString();
}
/**
* get positive characters
*
* @param n n > 0
* @return chars
*/
public static String getShortestPosChars(int n) {
StringBuilder stringBuilder = new StringBuilder();
while (n >= 128) {
stringBuilder.append(OffsetFont.POS_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.POS_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.POS_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.POS_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.POS_8.getCharacter());
n -= 8;
}
if (n - 7 >= 0) {
stringBuilder.append(OffsetFont.POS_7.getCharacter());
n -= 7;
}
if (n - 6 >= 0) {
stringBuilder.append(OffsetFont.POS_6.getCharacter());
n -= 6;
}
if (n - 5 >= 0) {
stringBuilder.append(OffsetFont.POS_5.getCharacter());
n -= 5;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.POS_4.getCharacter());
n -= 4;
}
if (n - 3 >= 0) {
stringBuilder.append(OffsetFont.POS_3.getCharacter());
n -= 3;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.POS_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.POS_1.getCharacter());
}
return stringBuilder.toString();
}
}
@@ -1,132 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.misc;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class ViewerText {
private final Player owner;
private String processedText;
private final ClaimedText[] placeholders;
private final ConcurrentHashMap<UUID, String> valueMap;
public ViewerText(Player owner, String rawText) {
this.processedText = rawText;
this.valueMap = new ConcurrentHashMap<>();
this.owner = owner;
List<String> placeholders = CustomNameplatesPlugin.get().getPlaceholderManager().detectPlaceholders(rawText);
this.placeholders = new ClaimedText[placeholders.size()];
int i = 0;
for (String placeholder : placeholders) {
processedText = processedText.replace(placeholder, "%s");
if (placeholder.startsWith("%viewer_")) {
this.placeholders[i] = new ClaimedText(null, "%" + placeholder.substring("%viewer_".length()));
} else {
this.placeholders[i] = new ClaimedText(owner, placeholder);
}
i++;
}
}
public void updateForOwner() {
for (ClaimedText text : placeholders) {
text.update();
}
}
public boolean updateForViewer(Player viewer) {
String string;
if ("%s".equals(processedText)) {
string = placeholders[0].getValue(viewer);
} else if (placeholders.length != 0) {
Object[] values = new String[placeholders.length];
for (int i = 0; i < placeholders.length; i++) {
values[i] = placeholders[i].getValue(viewer);
}
string = String.format(processedText, values);
} else {
string = processedText;
}
var uuid = viewer.getUniqueId();
if (!valueMap.containsKey(uuid)) {
valueMap.put(uuid, string);
return true;
}
String previousValue = valueMap.get(uuid);
if (!previousValue.equals(string)) {
valueMap.put(uuid, string);
return true;
}
return false;
}
public void removeViewer(Player viewer) {
valueMap.remove(viewer.getUniqueId());
}
public void clear() {
valueMap.clear();
}
public String getProcessedText() {
return processedText;
}
public String getLatestValue(Player viewer) {
return valueMap.get(viewer.getUniqueId());
}
public Entity getOwner() {
return owner;
}
public static class ClaimedText {
private final String placeholder;
private final Player owner;
private String latestValue;
public ClaimedText(Player owner, String placeholder) {
this.placeholder = placeholder;
this.owner = owner;
this.latestValue = null;
this.update();
}
public void update() {
if (owner == null) return;
this.latestValue = PlaceholderAPI.setPlaceholders(owner, placeholder);
}
public String getValue(Player viewer) {
return Objects.requireNonNullElseGet(
latestValue,
() -> PlaceholderAPI.setPlaceholders(owner == null ? viewer : owner, placeholder)
);
}
}
}
@@ -1,87 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.nameplate;
import net.momirealms.customnameplates.common.team.TeamColor;
public class CachedNameplate {
private TeamColor teamColor;
private String tagPrefix;
private String tagSuffix;
private String namePrefix;
private String nameSuffix;
private String playerName;
public CachedNameplate() {
this.tagPrefix = "";
this.tagSuffix = "";
this.namePrefix = "";
this.nameSuffix = "";
this.playerName = "";
this.teamColor = TeamColor.WHITE;
}
public String getTagPrefix() {
return tagPrefix;
}
public void setTagPrefix(String prefix) {
this.tagPrefix = prefix;
}
public String getTagSuffix() {
return tagSuffix;
}
public void setTagSuffix(String suffix) {
this.tagSuffix = suffix;
}
public void setNamePrefix(String namePrefix) {
this.namePrefix = namePrefix;
}
public void setNameSuffix(String nameSuffix) {
this.nameSuffix = nameSuffix;
}
public String getNamePrefix() {
return namePrefix;
}
public String getNameSuffix() {
return nameSuffix;
}
public TeamColor getTeamColor() {
return teamColor;
}
public void setTeamColor(TeamColor teamColor) {
this.teamColor = teamColor;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
}
@@ -1,187 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.nameplate;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.util.FontUtils;
import net.momirealms.customnameplates.common.team.TeamColor;
public class Nameplate {
private String displayName;
private TeamColor teamColor;
private String namePrefix;
private String nameSuffix;
private ConfiguredChar left;
private ConfiguredChar middle;
private ConfiguredChar right;
private Nameplate() {
}
public Nameplate(
String displayName,
TeamColor teamColor,
String namePrefix,
String nameSuffix,
ConfiguredChar left,
ConfiguredChar middle,
ConfiguredChar right
) {
this.displayName = displayName;
this.teamColor = teamColor;
this.left = left;
this.middle = middle;
this.right = right;
this.namePrefix = namePrefix;
this.nameSuffix = nameSuffix;
}
public String getDisplayName() {
return displayName;
}
public TeamColor getTeamColor() {
return teamColor;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getMiddle() {
return middle;
}
public ConfiguredChar getRight() {
return right;
}
public String getNamePrefix() {
if (teamColor == TeamColor.NONE) {
return "";
}
if (teamColor == TeamColor.CUSTOM) {
return namePrefix;
}
return "<" + teamColor.name() + ">";
}
public String getNameSuffix() {
if (teamColor == TeamColor.NONE) {
return "";
}
if (teamColor == TeamColor.CUSTOM) {
return nameSuffix;
}
return "</" + teamColor.name() + ">";
}
public static Builder builder() {
return new Builder();
}
public String getPrefixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getPrefix(textWidth));
}
public String getPrefix(int textWidth) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<#FEFEFE>");
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + left.getWidth() + 1));
stringBuilder.append(left.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
int mid_amount = (textWidth+2) / (middle.getWidth());
if (mid_amount != 0) {
for (int i = 0; i < mid_amount; i++) {
stringBuilder.append(middle.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - (textWidth+2) % middle.getWidth() + 1)); // +1
}
stringBuilder.append("</#FEFEFE>");
stringBuilder.append("<#FDFEFE>");
stringBuilder.append(middle.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(right.getCharacter());
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + right.getWidth() + 1)); // -1;
stringBuilder.append("</#FDFEFE>");
return stringBuilder.toString();
}
public String getSuffixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getSuffix(textWidth));
}
public String getSuffix(int textWidth) {
return OffsetFont.getShortestNegChars(textWidth + textWidth % 2 + 1);
}
public static class Builder {
private final Nameplate nameplate;
public Builder() {
this.nameplate = new Nameplate();
}
public static Builder of() {
return new Builder();
}
public Builder displayName(String display) {
nameplate.displayName = display;
return this;
}
public Builder teamColor(TeamColor teamColor) {
nameplate.teamColor = teamColor;
return this;
}
public Builder namePrefix(String namePrefix) {
nameplate.namePrefix = namePrefix;
return this;
}
public Builder nameSuffix(String nameSuffix) {
nameplate.nameSuffix = nameSuffix;
return this;
}
public Builder left(ConfiguredChar configuredChar) {
nameplate.left = configuredChar;
return this;
}
public Builder middle(ConfiguredChar configuredChar) {
nameplate.middle = configuredChar;
return this;
}
public Builder right(ConfiguredChar configuredChar) {
nameplate.right = configuredChar;
return this;
}
public Nameplate build() {
return nameplate;
}
}
}
@@ -1,91 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.background.BackGround;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class BackGroundText {
private String text;
private BackGround backGround;
private boolean removeShadow;
private BackGroundText() {
}
public BackGroundText(String text, BackGround backGround, boolean removeShadow) {
this.text = text;
this.backGround = backGround;
this.removeShadow = removeShadow;
}
public String getText() {
return text;
}
public BackGround getBackGround() {
return backGround;
}
public String getValue(OfflinePlayer player) {
String parsed = PlaceholderAPI.setPlaceholders(player, text);
if (parsed.equals("")) return "";
int parsedWidth = FontUtils.getTextWidth(parsed);
String bg = FontUtils.surroundNameplateFont(backGround.getBackGroundImage(parsedWidth));
return (removeShadow ? "<#FFFEFD>" + bg + "</#FFFEFD>" : bg)+ parsed;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final BackGroundText text;
public Builder() {
this.text = new BackGroundText();
}
public static Builder of() {
return new Builder();
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder background(BackGround backGround) {
text.backGround = backGround;
return this;
}
public Builder removeShadow(boolean remove) {
text.removeShadow = remove;
return this;
}
public BackGroundText build() {
return text;
}
}
}
@@ -1,71 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.placeholder;
public class CachedText {
private long refreshInterval;
private String text;
private CachedText() {
}
public CachedText(long refreshInterval, String text) {
this.refreshInterval = refreshInterval;
this.text = text;
}
public long getRefreshInterval() {
return refreshInterval;
}
public String getText() {
return text;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final CachedText text;
public Builder() {
this.text = new CachedText();
}
public static Builder of() {
return new Builder();
}
public Builder refreshInterval(long time) {
this.text.refreshInterval = time;
return this;
}
public Builder text(String text) {
this.text.text = text;
return this;
}
public CachedText build() {
return text;
}
}
}
@@ -1,75 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.manager.RequirementManager;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.common.Pair;
import org.bukkit.OfflinePlayer;
import java.util.List;
public class ConditionalText {
private List<Pair<String, Requirement[]>> textList;
private ConditionalText() {
}
public ConditionalText(List<Pair<String, Requirement[]>> textList) {
this.textList = textList;
}
public static Builder builder() {
return new Builder();
}
public String getValue(OfflinePlayer player) {
Condition condition = new Condition(player);
for (Pair<String, Requirement[]> pair : textList) {
if (RequirementManager.isRequirementMet(condition, pair.right())) {
return PlaceholderAPI.setPlaceholders(player, pair.left());
}
}
return "";
}
public static class Builder {
private final ConditionalText conditionalText;
public static Builder of() {
return new Builder();
}
public Builder() {
this.conditionalText = new ConditionalText();
}
public Builder textList(List<Pair<String, Requirement[]>> textList) {
conditionalText.textList = textList;
return this;
}
public ConditionalText build() {
return conditionalText;
}
}
}
@@ -1,93 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class DescentText {
private int ascent;
private String text;
private boolean isUnicode;
public DescentText(int ascent, String text, boolean isUnicode) {
this.ascent = ascent;
this.text = text;
this.isUnicode = isUnicode;
}
private DescentText() {
}
public int getAscent() {
return ascent;
}
public boolean isUnicode() {
return isUnicode;
}
public static Builder builder() {
return new Builder();
}
public String getValue(OfflinePlayer player) {
var parsed = PlaceholderAPI.setPlaceholders(player, text);
return FontUtils.surroundAscentFont(parsed, ascent);
}
public static class Builder {
private final DescentText descentText;
public static Builder of() {
return new Builder();
}
public Builder() {
this.descentText = new DescentText();
}
public Builder ascent(int ascent) {
descentText.ascent = ascent;
return this;
}
public Builder descent(int descent) {
descentText.ascent = 8 - descent;
return this;
}
public Builder text(String text) {
descentText.text = text;
return this;
}
public Builder unicode(boolean unicode) {
descentText.isUnicode = unicode;
return this;
}
public DescentText build() {
return descentText;
}
}
}
@@ -1,88 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class NameplateText {
private String text;
private Nameplate nameplate;
private NameplateText() {
}
public NameplateText(String text, Nameplate nameplate) {
this.text = text;
this.nameplate = nameplate;
}
public String getText() {
return text;
}
public Nameplate getNameplate() {
return nameplate;
}
public String getValue(OfflinePlayer player) {
String temp;
switch (nameplate.getTeamColor()) {
case CUSTOM -> temp = nameplate.getNamePrefix() + text + nameplate.getNameSuffix();
case NONE -> temp = text;
default -> temp = "<" + nameplate.getTeamColor().name() + ">" + text + "</" + nameplate.getTeamColor().name() + ">";
}
String parsed = PlaceholderAPI.setPlaceholders(player, temp);
int parsedWidth = FontUtils.getTextWidth(parsed);
return nameplate.getPrefixWithFont(parsedWidth) + parsed + nameplate.getSuffixWithFont(parsedWidth);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final NameplateText text;
public Builder() {
this.text = new NameplateText();
}
public static Builder of() {
return new Builder();
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder nameplate(Nameplate value) {
text.nameplate = value;
return this;
}
public NameplateText build() {
return text;
}
}
}
@@ -1,115 +0,0 @@
/*
* Copyright (C) <2022> <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.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class StaticText {
private String text;
private int value;
private StaticState staticState;
private StaticText() {
}
public StaticText(String text, int value, StaticState staticState) {
this.text = text;
this.value = value;
this.staticState = staticState;
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
public static Builder builder() {
return new Builder();
}
public StaticState getStaticState() {
return staticState;
}
public String getValue(OfflinePlayer player) {
String parsed = PlaceholderAPI.setPlaceholders(player, text);
int parsedWidth = FontUtils.getTextWidth(parsed);
switch (staticState) {
case LEFT -> {
return parsed + FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(value - parsedWidth));
}
case RIGHT -> {
return FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(value - parsedWidth)) + parsed;
}
case MIDDLE -> {
int half = (value - parsedWidth) / 2;
String left = FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(half));
String right = FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(value - parsedWidth - half));
return left + parsed + right;
}
default -> {
return "";
}
}
}
public static class Builder {
private final StaticText text;
public Builder() {
this.text = new StaticText();
}
public static Builder of() {
return new Builder();
}
public Builder value(int value) {
text.value = value;
return this;
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder state(StaticState state) {
text.staticState = state;
return this;
}
public StaticText build() {
return text;
}
}
public enum StaticState {
LEFT,
MIDDLE,
RIGHT
}
}
Loaded 100 of 892 files, more files were not shown because too many files have changed in this diff. Show more