mirror of
https://github.com/Xiao-MoMi/Custom-Nameplates.git
synced 2025-12-19 15:09:23 +00:00
3.0
This commit is contained in:
49
README.md
49
README.md
@@ -1,44 +1,37 @@
|
||||
# This project is undergoing a major refactoring
|
||||
|
||||
# Custom-Nameplates
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
[](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>
|
||||
|
||||
CustomNameplates is a Paper plugin that provides unlimited customization for nametags, bossbars, actionbars and chat bubbles.
|
||||
[](https://github.com/Xiao-MoMi/Custom-Nameplates/)
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## 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>
|
||||
@@ -46,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}")
|
||||
}
|
||||
```
|
||||
@@ -1,8 +1,28 @@
|
||||
plugins {
|
||||
id("io.github.goooler.shadow") version "8.1.8"
|
||||
}
|
||||
|
||||
repositories {
|
||||
}
|
||||
|
||||
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.16.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")
|
||||
// FOP
|
||||
compileOnly("org.apache.pdfbox:fontbox:${rootProject.properties["fontbox_version"]}")
|
||||
// COMMONS IO
|
||||
compileOnly("commons-io:commons-io:${rootProject.properties["commons_io_version"]}")
|
||||
// GSON
|
||||
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
BIN
api/libs/boosted-yaml-1.3.7.jar
Normal file
BIN
api/libs/boosted-yaml-1.3.7.jar
Normal file
Binary file not shown.
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* 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.Feature;
|
||||
import net.momirealms.customnameplates.api.feature.TickStampData;
|
||||
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 java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
|
||||
protected final CustomNameplates plugin;
|
||||
protected final Object player;
|
||||
|
||||
private boolean isLoaded = false;
|
||||
|
||||
private boolean isPreviewing = false;
|
||||
|
||||
private String equippedNameplate;
|
||||
private String equippedBubble;
|
||||
|
||||
/**
|
||||
* 此处缓存了所有解析过的变量,Relational则是缓存了与某个玩家的关系变量,仅更新当前处于active状态的变量。
|
||||
*/
|
||||
private final Map<Integer, TickStampData<String>> cachedValues = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TickStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 此处缓存了所有解析过的条件,Relational则是缓存了与某个玩家的关系条件
|
||||
*/
|
||||
private final Map<Requirement, TickStampData<Boolean>> cachedRequirements = new ConcurrentHashMap<>();
|
||||
private final Map<Requirement, WeakHashMap<CNPlayer, TickStampData<Boolean>>> cachedRelationalRequirements = new ConcurrentHashMap<>();
|
||||
|
||||
/*
|
||||
* 这里维护了一个双向的Map以方便更新对应的Feature。
|
||||
* 插件会先获取当前处于活跃状态的变量(由Feature提供),根据变量的更新情况,判断是否需要反馈到对应的Feature以便只在必要的时刻进行更新
|
||||
*/
|
||||
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, Object player) {
|
||||
this.plugin = plugin;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有处于激活状态的变量统筹起来并返回一个更新任务
|
||||
*
|
||||
* @return 更新任务
|
||||
*/
|
||||
@Override
|
||||
public List<Placeholder> getRefreshValueTask() {
|
||||
Placeholder[] activePlaceholders = activePlaceholders();
|
||||
List<Placeholder> placeholderWithChildren = new ArrayList<>();
|
||||
for (Placeholder placeholder : activePlaceholders) {
|
||||
childrenFirstList(placeholder, placeholderWithChildren);
|
||||
}
|
||||
List<Placeholder> uniquePlaceholderWithChildren = placeholderWithChildren.stream().distinct().toList();
|
||||
List<Placeholder> placeholdersToUpdate = new ArrayList<>();
|
||||
for (Placeholder placeholder : uniquePlaceholderWithChildren) {
|
||||
int interval = placeholder.refreshInterval();
|
||||
if (interval > 0 && MainTask.getTicks() % interval == 0) {
|
||||
placeholdersToUpdate.add(placeholder);
|
||||
}
|
||||
}
|
||||
return placeholdersToUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceUpdate(Set<Placeholder> placeholders, Set<CNPlayer> others) {
|
||||
if (placeholders.isEmpty()) return;
|
||||
List<Placeholder> placeholderWithChildren = new ArrayList<>();
|
||||
for (Placeholder placeholder : placeholders) {
|
||||
childrenFirstList(placeholder, placeholderWithChildren);
|
||||
}
|
||||
for (Placeholder placeholder : placeholderWithChildren) {
|
||||
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
|
||||
TickStampData<String> value = getValue(placeholder);
|
||||
if (value == null) {
|
||||
value = new TickStampData<>(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) {
|
||||
TickStampData<String> value = getRelationalValue(placeholder, player);
|
||||
if (value == null) {
|
||||
value = new TickStampData<>(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) {
|
||||
TickStampData<String> value = getValue(placeholder);
|
||||
if (value == null) {
|
||||
String latest;
|
||||
if (MainTask.hasRequested(sharedPlaceholder.countId())) {
|
||||
latest = sharedPlaceholder.getLatestValue();
|
||||
} else {
|
||||
latest = sharedPlaceholder.request();
|
||||
}
|
||||
value = new TickStampData<>(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);
|
||||
}
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
cachedValues.clear();
|
||||
cachedRelationalValues.clear();
|
||||
activeFeatures.clear();
|
||||
placeholder2Features.clear();
|
||||
feature2Placeholders.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Feature> getUsedFeatures(Placeholder placeholder) {
|
||||
return placeholder2Features.getOrDefault(placeholder, Collections.emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object player() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public void setLoaded(boolean loaded) {
|
||||
isLoaded = loaded;
|
||||
}
|
||||
|
||||
public void setPreviewing(boolean previewing) {
|
||||
isPreviewing = previewing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreviewing() {
|
||||
return isPreviewing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFeature(Feature feature) {
|
||||
activeFeatures.add(feature);
|
||||
Set<Placeholder> allPlaceholdersUsedInFeature = feature.allPlaceholders();
|
||||
feature2Placeholders.put(feature, allPlaceholdersUsedInFeature);
|
||||
for (Placeholder placeholder : allPlaceholdersUsedInFeature) {
|
||||
Set<Feature> featureSet = placeholder2Features.computeIfAbsent(placeholder, k -> {
|
||||
forceUpdate(Set.of(placeholder), nearbyPlayers());
|
||||
return 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, TickStampData<String> value) {
|
||||
cachedValues.put(placeholder.countId(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setValue(Placeholder placeholder, String value) {
|
||||
TickStampData<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 TickStampData<>(value, currentTicks, true);
|
||||
cachedValues.put(placeholder.countId(), previous);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRelationalValue(Placeholder placeholder, CNPlayer another, TickStampData<String> value) {
|
||||
WeakHashMap<CNPlayer, TickStampData<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, TickStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
|
||||
TickStampData<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 TickStampData<>(value, currentTicks, true);
|
||||
map.put(another, previous);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getData(Placeholder placeholder) {
|
||||
return Optional.ofNullable(cachedValues.get(placeholder.countId())).map(TickStampData::data).orElse(placeholder.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickStampData<String> getValue(Placeholder placeholder) {
|
||||
return cachedValues.get(placeholder.countId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelationalData(Placeholder placeholder, CNPlayer another) {
|
||||
WeakHashMap<CNPlayer, TickStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
return Optional.ofNullable(map.get(another)).map(TickStampData::data).orElse(placeholder.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another) {
|
||||
WeakHashMap<CNPlayer, TickStampData<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) {
|
||||
TickStampData<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 TickStampData<>(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, TickStampData<Boolean>> innerMap = cachedRelationalRequirements.computeIfAbsent(requirement, k -> new WeakHashMap<>());
|
||||
TickStampData<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 TickStampData<>(satisfied, currentTicks, true);
|
||||
innerMap.put(another, data);
|
||||
if (!satisfied) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracker addPlayerToTracker(CNPlayer another) {
|
||||
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 -> new HashSet<>(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 void equippedBubble(String equippedBubble) {
|
||||
if (!equippedBubble.equals(this.equippedBubble)) {
|
||||
this.equippedBubble = equippedBubble;
|
||||
// TODO 更新变量
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String equippedNameplate() {
|
||||
if (equippedNameplate == null) return "none";
|
||||
return equippedNameplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void equippedNameplate(String equippedNameplate) {
|
||||
if (!equippedNameplate.equals(this.equippedNameplate)) {
|
||||
this.equippedNameplate = equippedNameplate;
|
||||
// TODO 更新变量
|
||||
}
|
||||
}
|
||||
|
||||
@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,118 @@
|
||||
/*
|
||||
* 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.Feature;
|
||||
import net.momirealms.customnameplates.api.feature.TickStampData;
|
||||
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 java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface CNPlayer {
|
||||
|
||||
String name();
|
||||
|
||||
UUID uuid();
|
||||
|
||||
int entityID();
|
||||
|
||||
Vector3 position();
|
||||
|
||||
String world();
|
||||
|
||||
void forceUpdate(Set<Placeholder> placeholders, Set<CNPlayer> another);
|
||||
|
||||
Set<Feature> getUsedFeatures(Placeholder placeholder);
|
||||
|
||||
Object player();
|
||||
|
||||
double scale();
|
||||
|
||||
boolean isCrouching();
|
||||
|
||||
boolean isLoaded();
|
||||
|
||||
boolean isPreviewing();
|
||||
|
||||
boolean hasPermission(String permission);
|
||||
|
||||
long playerTime();
|
||||
|
||||
List<Placeholder> getRefreshValueTask();
|
||||
|
||||
Placeholder[] activePlaceholders();
|
||||
|
||||
boolean isOnline();
|
||||
|
||||
String getData(Placeholder placeholder);
|
||||
|
||||
TickStampData<String> getValue(Placeholder placeholder);
|
||||
|
||||
String getRelationalData(Placeholder placeholder, CNPlayer another);
|
||||
|
||||
TickStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another);
|
||||
|
||||
void setValue(Placeholder placeholder, TickStampData<String> value);
|
||||
|
||||
boolean setValue(Placeholder placeholder, String value);
|
||||
|
||||
void setRelationalValue(Placeholder placeholder, CNPlayer another, TickStampData<String> value);
|
||||
|
||||
boolean setRelationalValue(Placeholder placeholder, CNPlayer another, String value);
|
||||
|
||||
void addFeature(Feature feature);
|
||||
|
||||
void removeFeature(Feature feature);
|
||||
|
||||
boolean isMet(Requirement[] requirements);
|
||||
|
||||
boolean isMet(CNPlayer another, Requirement[] requirements);
|
||||
|
||||
Tracker addPlayerToTracker(CNPlayer another);
|
||||
|
||||
void removePlayerFromTracker(CNPlayer another);
|
||||
|
||||
Set<CNPlayer> nearbyPlayers();
|
||||
|
||||
void trackPassengers(CNPlayer another, int... passengers);
|
||||
|
||||
void untrackPassengers(CNPlayer another, int... passengers);
|
||||
|
||||
Set<Integer> getTrackedPassengerIds(CNPlayer another);
|
||||
|
||||
Set<Integer> passengers();
|
||||
|
||||
boolean isFlying();
|
||||
|
||||
Tracker getTracker(CNPlayer another);
|
||||
|
||||
String equippedBubble();
|
||||
|
||||
void equippedBubble(String equippedBubble);
|
||||
|
||||
String equippedNameplate();
|
||||
|
||||
void equippedNameplate(String equippedNameplate);
|
||||
|
||||
int remainingAir();
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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.bossbar.BossBar;
|
||||
import net.momirealms.customnameplates.api.feature.pack.CharacterArranger;
|
||||
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 actionbarModule;
|
||||
protected boolean imageModule;
|
||||
protected boolean bossBarModule;
|
||||
protected boolean bubbleModule;
|
||||
protected boolean nameplateModule;
|
||||
protected boolean backgroundModule;
|
||||
protected int defaultRefreshInterval;
|
||||
protected int delaySend;
|
||||
protected boolean catchOtherActionBar;
|
||||
|
||||
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 chatUnsafe;
|
||||
protected boolean chatTR;
|
||||
protected boolean chatVenture;
|
||||
protected boolean chatHusk;
|
||||
protected boolean chatCarbon;
|
||||
protected boolean chatAdvanced;
|
||||
protected boolean chatEss;
|
||||
|
||||
public ConfigManager(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
String configVersion = CustomNameplatesProperties.getValue("config");
|
||||
try (InputStream inputStream = new FileInputStream(resolveConfig("config.yml").toFile())) {
|
||||
MAIN_CONFIG = YamlDocument.create(
|
||||
inputStream,
|
||||
plugin.getResourceStream("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()
|
||||
);
|
||||
MAIN_CONFIG.save(resolveConfig("config.yml").toFile());
|
||||
loadSettings();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
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);
|
||||
defaultRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 10);
|
||||
catchOtherActionBar = config.getBoolean("other-settings.catch-other-plugin-actionbar", 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 char initialChar() {
|
||||
return instance.initialChar;
|
||||
}
|
||||
|
||||
public static boolean actionbarModule() {
|
||||
return instance.actionbarModule;
|
||||
}
|
||||
|
||||
public static boolean catchOtherActionBar() {
|
||||
return instance.catchOtherActionBar;
|
||||
}
|
||||
|
||||
public static boolean packItemsAdder() {
|
||||
return instance.packItemsAdder;
|
||||
}
|
||||
|
||||
public static boolean packItemsAdderLegacy() {
|
||||
return instance.packItemsAdderLegacy;
|
||||
}
|
||||
|
||||
public static boolean packOraxen() {
|
||||
return instance.packOraxen;
|
||||
}
|
||||
|
||||
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 defaultRefreshInterval() {
|
||||
return instance.defaultRefreshInterval;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
protected 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,191 @@
|
||||
/*
|
||||
* 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.bubble.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.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
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 = new MainTask(this);
|
||||
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 CustomNameplates() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
if (scheduledMainTask != null)
|
||||
scheduledMainTask.cancel();
|
||||
scheduledMainTask = getScheduler().asyncRepeating(mainTask, 50, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
if (this.scheduledMainTask != null) this.scheduledMainTask.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyManager getDependencyManager() {
|
||||
return dependencyManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslationManager getTranslationManager() {
|
||||
return translationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Supplier<String> supplier) {
|
||||
this.debugger.accept(supplier);
|
||||
}
|
||||
|
||||
public PlaceholderManager getPlaceholderManager() {
|
||||
return placeholderManager;
|
||||
}
|
||||
|
||||
public PacketSender getPacketSender() {
|
||||
return packetSender;
|
||||
}
|
||||
|
||||
public RequirementManager getRequirementManager() {
|
||||
return requirementManager;
|
||||
}
|
||||
|
||||
public ActionBarManager getActionBarManager() {
|
||||
return actionBarManager;
|
||||
}
|
||||
|
||||
public UnlimitedTagManager getUnlimitedTagManager() {
|
||||
return unlimitedTagManager;
|
||||
}
|
||||
|
||||
public AdvanceManager getAdvanceManager() {
|
||||
return advanceManager;
|
||||
}
|
||||
|
||||
public BackgroundManager getBackgroundManager() {
|
||||
return backgroundManager;
|
||||
}
|
||||
|
||||
public EventManager getEventManager() {
|
||||
return eventManager;
|
||||
}
|
||||
|
||||
public StorageManager getStorageManager() {
|
||||
return storageManager;
|
||||
}
|
||||
|
||||
public NameplateManager getNameplateManager() {
|
||||
return nameplateManager;
|
||||
}
|
||||
|
||||
public ImageManager getImageManager() {
|
||||
return imageManager;
|
||||
}
|
||||
|
||||
public BubbleManager getBubbleManager() {
|
||||
return bubbleManager;
|
||||
}
|
||||
|
||||
public ChatManager getChatManager() {
|
||||
return chatManager;
|
||||
}
|
||||
|
||||
public ResourcePackManager getResourcePackManager() {
|
||||
return resourcePackManager;
|
||||
}
|
||||
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public Collection<CNPlayer> getOnlinePlayers() {
|
||||
return new HashSet<>(onlinePlayerMap.values());
|
||||
}
|
||||
|
||||
public CNPlayer getPlayer(UUID uuid) {
|
||||
return onlinePlayerMap.get(uuid);
|
||||
}
|
||||
|
||||
public CNPlayer getPlayer(int entityID) {
|
||||
return entityIDFastLookup.get(entityID);
|
||||
}
|
||||
|
||||
public static CustomNameplates getInstance() {
|
||||
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,128 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
// The system would break if a server hasn't stopped for 3 years
|
||||
private static int TICKS = 0;
|
||||
|
||||
private static final Map<Integer, Integer> TIME_1 = new ConcurrentHashMap<>(2048, 1F);
|
||||
private static final Map<Integer, Integer> TIME_2 = new ConcurrentHashMap<>(2048, 1F);
|
||||
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 TICKS;
|
||||
}
|
||||
|
||||
public static boolean hasRequested(int countId) {
|
||||
boolean result = requestedSharedPlaceholders.contains(countId);
|
||||
if (!result) requestedSharedPlaceholders.add(countId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 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;
|
||||
}
|
||||
|
||||
public static HealthyProfile getHealthyProfile() {
|
||||
long total1 = 0;
|
||||
long total2 = 0;
|
||||
for (int value : TIME_1.values()) {
|
||||
total1 += value;
|
||||
}
|
||||
for (int value : TIME_2.values()) {
|
||||
total2 += value;
|
||||
}
|
||||
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,77 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface Platform {
|
||||
|
||||
Object jsonToMinecraftComponent(String json);
|
||||
|
||||
String minecraftComponentToJson(Object component);
|
||||
|
||||
Object vec3(double x, double y, double z);
|
||||
|
||||
Placeholder registerPlatformPlaceholder(String id);
|
||||
|
||||
void onPacketSend(CNPlayer player, PacketEvent event);
|
||||
|
||||
Object setActionBarTextPacket(Object component);
|
||||
|
||||
Object createBossBarPacket(UUID uuid, Object component, float progress, BossBar.Overlay overlay, BossBar.Color color);
|
||||
|
||||
Object removeBossBarPacket(UUID uuid);
|
||||
|
||||
Object updateBossBarNamePacket(UUID uuid, Object component);
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
Consumer<List<Object>> createInterpolationDelayModifier(int delay);
|
||||
|
||||
Consumer<List<Object>> createTransformationInterpolationDurationModifier(int duration);
|
||||
|
||||
Consumer<List<Object>> createTextComponentModifier(Object component);
|
||||
|
||||
Consumer<List<Object>> createScaleModifier(Vector3 scale);
|
||||
|
||||
Consumer<List<Object>> createTranslationModifier(Vector3 translation);
|
||||
|
||||
Consumer<List<Object>> createOpacityModifier(byte opacity);
|
||||
|
||||
Object updateTextDisplayPacket(int entityID, List<Consumer<List<Object>>> modifiers);
|
||||
|
||||
Object setPassengersPacket(int vehicle, int[] passengers);
|
||||
|
||||
Object removeEntityPacket(int... entityID);
|
||||
}
|
||||
@@ -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,33 +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.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface LegacyDataStorageInterface extends DataStorageInterface {
|
||||
|
||||
/**
|
||||
* Retrieve legacy player data from the SQL database.
|
||||
*
|
||||
* @param uuid The UUID of the player.
|
||||
* @return A CompletableFuture containing the optional legacy player data.
|
||||
*/
|
||||
CompletableFuture<Optional<PlayerData>> getLegacyPlayerData(UUID uuid);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,17 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.api.mechanic.tag;
|
||||
package net.momirealms.customnameplates.api.event;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import net.momirealms.customnameplates.api.storage.data.PlayerData;
|
||||
import net.momirealms.customnameplates.common.event.Param;
|
||||
|
||||
public interface NameplatePlayer {
|
||||
public interface DataLoadEvent {
|
||||
|
||||
void setPreview(boolean preview);
|
||||
|
||||
boolean isPreviewing();
|
||||
|
||||
Player getPlayer();
|
||||
|
||||
void updateText();
|
||||
@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();
|
||||
}
|
||||
}
|
||||
@@ -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,11 +15,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.message;
|
||||
package net.momirealms.customnameplates.api.event;
|
||||
|
||||
public class MessageType {
|
||||
import net.momirealms.customnameplates.common.event.Cancellable;
|
||||
import net.momirealms.customnameplates.common.event.NameplatesEvent;
|
||||
|
||||
public static final String CREATE = "0";
|
||||
public static final String REMOVE = "1";
|
||||
public static final String UPDATE = "2";
|
||||
public interface NameplatesReloadEvent extends NameplatesEvent, Cancellable {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
String createImagePrefix(float advance, float leftMargin, float rightMargin);
|
||||
|
||||
String createImageSuffix(float advance, float leftMargin, float rightMargin);
|
||||
|
||||
String createImage(float advance, float leftMargin, float rightMargin);
|
||||
}
|
||||
@@ -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.requirement.Requirement;
|
||||
|
||||
public class CarouselText {
|
||||
|
||||
private final int duration;
|
||||
private final Requirement[] requirements;
|
||||
private final String rawText;
|
||||
private final PreParsedDynamicText preParsedDynamicText;
|
||||
private final boolean updateOnDisplay;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public int duration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public Requirement[] requirements() {
|
||||
return requirements;
|
||||
}
|
||||
|
||||
public String text() {
|
||||
return rawText;
|
||||
}
|
||||
|
||||
public PreParsedDynamicText preParsedDynamicText() {
|
||||
return preParsedDynamicText;
|
||||
}
|
||||
|
||||
public boolean updateOnDisplay() {
|
||||
return updateOnDisplay;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface ChatListener {
|
||||
|
||||
void onPlayerChat(CNPlayer player, String message, String channel);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 net.momirealms.customnameplates.api.feature.pack.CharacterArranger;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ConfiguredCharacter {
|
||||
|
||||
private final char character;
|
||||
private final File imageFile;
|
||||
|
||||
private final int height;
|
||||
private final int ascent;
|
||||
|
||||
private final float advance;
|
||||
|
||||
public static ConfiguredCharacter create(File imageFile, int ascent, int height) {
|
||||
return new ConfiguredCharacter(CharacterArranger.getAndIncrease(), imageFile, ascent, height);
|
||||
}
|
||||
|
||||
public static ConfiguredCharacter create(File imageFile, int ascent, int height, float advance) {
|
||||
return new ConfiguredCharacter(CharacterArranger.getAndIncrease(), imageFile, ascent, height, advance);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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). " + imageFile.getAbsolutePath(), ascent, height));
|
||||
}
|
||||
try {
|
||||
BufferedImage bufferedImage = ImageIO.read(imageFile);
|
||||
int imageHeight = bufferedImage.getHeight();
|
||||
int imageWidth = bufferedImage.getWidth();
|
||||
|
||||
float scale = (float) height / (float) 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 = (int) (0.5 + (double) ((i+1f) * scale)) + 1f;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public char character() {
|
||||
return character;
|
||||
}
|
||||
|
||||
public int ascent() {
|
||||
return ascent;
|
||||
}
|
||||
|
||||
public float advance() {
|
||||
return advance;
|
||||
}
|
||||
|
||||
public int height() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public File imageFile() {
|
||||
return imageFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class DynamicText {
|
||||
|
||||
private final String text;
|
||||
private final List<Function<CNPlayer, String>> texts;
|
||||
private final Set<Placeholder> placeholders;
|
||||
|
||||
public DynamicText(String text, List<Function<CNPlayer, String>> texts, Set<Placeholder> placeholders) {
|
||||
this.text = text;
|
||||
this.texts = texts;
|
||||
this.placeholders = placeholders;
|
||||
}
|
||||
|
||||
public Set<Placeholder> placeholders() {
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
public String render(CNPlayer viewer) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Function<CNPlayer, String> function : texts) {
|
||||
builder.append(function.apply(viewer));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public String text() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface Feature {
|
||||
|
||||
String name();
|
||||
|
||||
Set<Placeholder> activePlaceholders();
|
||||
|
||||
Set<Placeholder> allPlaceholders();
|
||||
|
||||
void notifyPlaceholderUpdates(CNPlayer p1, boolean force);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface JoinQuitListener {
|
||||
|
||||
void onPlayerJoin(CNPlayer player);
|
||||
|
||||
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,120 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
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 = text;
|
||||
}
|
||||
|
||||
public PreParsedDynamicText(String text, boolean init) {
|
||||
this.text = 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,25 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface RelationalFeature extends Feature {
|
||||
|
||||
void notifyPlaceholderUpdates(CNPlayer p1, CNPlayer p2, boolean force);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class TickStampData<D> {
|
||||
|
||||
private D data;
|
||||
private int packedTicks;
|
||||
|
||||
public TickStampData(D data, int ticks, boolean changed) {
|
||||
this.data = data;
|
||||
this.packedTicks = packBooleanAndTicks(changed, ticks);
|
||||
}
|
||||
|
||||
public void data(D data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void updateTicks(boolean changed) {
|
||||
this.packedTicks = packBooleanAndTicks(changed, MainTask.getTicks());
|
||||
}
|
||||
|
||||
public D data() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public boolean hasValueChanged() {
|
||||
return unpackBoolean(packedTicks);
|
||||
}
|
||||
|
||||
public int ticks() {
|
||||
return unpackTicks(packedTicks);
|
||||
}
|
||||
|
||||
public static int packBooleanAndTicks(boolean hasValueChanged, int ticks) {
|
||||
int numberMasked = ticks & 0x7FFFFFFF;
|
||||
int booleanBit = hasValueChanged ? 1 << 31 : 0;
|
||||
return booleanBit | numberMasked;
|
||||
}
|
||||
|
||||
public static int unpackTicks(int packed) {
|
||||
return packed & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
public static boolean unpackBoolean(int packed) {
|
||||
return (packed & 0x80000000) != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
String id();
|
||||
|
||||
Requirement[] requirements();
|
||||
|
||||
CarouselText[] carouselTexts();
|
||||
|
||||
static Builder builder() {
|
||||
return new ActionBarConfigImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder requirement(Requirement[] requirements);
|
||||
|
||||
Builder carouselText(CarouselText[] carouselTexts);
|
||||
|
||||
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,34 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface ActionBarManager extends Reloadable {
|
||||
|
||||
void refreshConditions();
|
||||
|
||||
void checkHeartBeats();
|
||||
|
||||
ActionBarConfig getConfig(String name);
|
||||
|
||||
ActionBarConfig[] allConfigs();
|
||||
|
||||
String getExternalActionBar(CNPlayer player);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.feature.JoinQuitListener;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ActionBarManagerImpl implements ActionBarManager, JoinQuitListener {
|
||||
|
||||
protected final CustomNameplates plugin;
|
||||
private final LinkedHashMap<String, ActionBarConfig> configs = new LinkedHashMap<>();
|
||||
private final ConcurrentHashMap<UUID, ActionBarSender> senders = new ConcurrentHashMap<>();
|
||||
private ActionBarConfig[] configArray = new ActionBarConfig[0];
|
||||
|
||||
public ActionBarManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// ignore disabled modules
|
||||
if (!ConfigManager.actionbarModule()) return;
|
||||
this.loadConfig();
|
||||
this.resetArray();
|
||||
for (CNPlayer online : plugin.getOnlinePlayers()) {
|
||||
onPlayerJoin(online);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
for (ActionBarSender sender : senders.values()) {
|
||||
sender.destroy();
|
||||
}
|
||||
this.senders.clear();
|
||||
this.configs.clear();
|
||||
this.resetArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshConditions() {
|
||||
for (ActionBarSender sender : senders.values()) {
|
||||
sender.onConditionTimerCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkHeartBeats() {
|
||||
for (ActionBarSender sender : senders.values()) {
|
||||
sender.onHeartBeatTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private void resetArray() {
|
||||
configArray = configs.values().toArray(new ActionBarConfig[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionBarConfig getConfig(String name) {
|
||||
return configs.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionBarConfig[] allConfigs() {
|
||||
return configArray;
|
||||
}
|
||||
|
||||
public void handleActionBarPacket(CNPlayer player, String miniMessage) {
|
||||
ActionBarSender sender = senders.get(player.uuid());
|
||||
if (sender != null) {
|
||||
sender.externalActionBar(miniMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalActionBar(CNPlayer player) {
|
||||
ActionBarSender sender = senders.get(player.uuid());
|
||||
if (sender != null) {
|
||||
return sender.externalActionBar();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerJoin(CNPlayer player) {
|
||||
if (!ConfigManager.actionbarModule()) return;
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
if (!player.isOnline()) return;
|
||||
ActionBarSender sender = new ActionBarSender(this, player);
|
||||
ActionBarSender previous = senders.put(player.uuid(), sender);
|
||||
if (previous != null) {
|
||||
previous.destroy();
|
||||
}
|
||||
}, ConfigManager.delaySend() * 50L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerQuit(CNPlayer player) {
|
||||
ActionBarSender sender = senders.remove(player.uuid());
|
||||
if (sender != null) {
|
||||
sender.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
plugin.getConfigManager().saveResource("configs" + File.separator + "actionbar.yml");
|
||||
YamlDocument document = plugin.getConfigManager().loadData(new File(plugin.getDataDirectory().toFile(), "configs" + File.separator + "actionbar.yml"));
|
||||
for (Map.Entry<String, Object> entry : document.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (!(entry.getValue() instanceof Section section))
|
||||
return;
|
||||
this.configs.put(entry.getKey(),
|
||||
ActionBarConfig.builder()
|
||||
.id(entry.getKey())
|
||||
.requirement(plugin.getRequirementManager().parseRequirements(section.getSection("conditions")))
|
||||
.carouselText(
|
||||
section.contains("text") ?
|
||||
new CarouselText[]{new CarouselText(-1, new Requirement[0], section.getString("text"), false)} :
|
||||
ConfigUtils.carouselTexts(section.getSection("text-display-order"))
|
||||
)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.feature.DynamicText;
|
||||
import net.momirealms.customnameplates.api.feature.Feature;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
import net.momirealms.customnameplates.api.placeholder.Placeholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class ActionBarSender implements Feature {
|
||||
|
||||
private final ActionBarManager manager;
|
||||
private final CNPlayer owner;
|
||||
private long lastUpdateTime;
|
||||
|
||||
private ActionBarConfig currentConfig;
|
||||
private int order;
|
||||
private int timeLeft;
|
||||
private DynamicText currentActionBar;
|
||||
|
||||
private String externalActionBar;
|
||||
private long externalExpireTime;
|
||||
|
||||
private String latestContent;
|
||||
|
||||
private boolean textChangeFlag = false;
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "ActionBarSender";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ActionBarSender sender = (ActionBarSender) o;
|
||||
return owner == sender.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return owner.name().hashCode();
|
||||
}
|
||||
|
||||
public ActionBarSender(ActionBarManager manager, CNPlayer owner) {
|
||||
this.owner = owner;
|
||||
this.manager = manager;
|
||||
this.owner.addFeature(this);
|
||||
this.onConditionTimerCheck();
|
||||
}
|
||||
|
||||
public void onConditionTimerCheck() {
|
||||
ActionBarConfig[] configs = manager.allConfigs();
|
||||
outer: {
|
||||
for (ActionBarConfig config : configs) {
|
||||
if (owner.isMet(config.requirements())) {
|
||||
if (config != currentConfig) {
|
||||
currentConfig = config;
|
||||
order = config.carouselTexts().length - 1;
|
||||
timeLeft = 0;
|
||||
}
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
|
||||
// no actionbar available
|
||||
currentConfig = null;
|
||||
currentActionBar = null;
|
||||
latestContent = null;
|
||||
}
|
||||
|
||||
if (currentConfig != null) {
|
||||
|
||||
if (timeLeft > 0)
|
||||
timeLeft--;
|
||||
|
||||
if (timeLeft == 0) {
|
||||
int triedTimes = 0;
|
||||
|
||||
do {
|
||||
if (triedTimes == currentConfig.carouselTexts().length) {
|
||||
timeLeft = 20;
|
||||
latestContent = null;
|
||||
CustomNameplates.getInstance().getPluginLogger().warn("No text in order is available for player " + owner.name() + ". Please check your actionbar's conditions.");
|
||||
return;
|
||||
}
|
||||
order++;
|
||||
if (order >= currentConfig.carouselTexts().length) {
|
||||
order = 0;
|
||||
}
|
||||
triedTimes++;
|
||||
} while (
|
||||
!owner.isMet(currentConfig.carouselTexts()[order].requirements())
|
||||
);
|
||||
|
||||
CarouselText carouselText = currentConfig.carouselTexts()[order];
|
||||
timeLeft = carouselText.duration();
|
||||
currentActionBar = carouselText.preParsedDynamicText().fastCreate(owner);
|
||||
|
||||
if (carouselText.updateOnDisplay()) {
|
||||
owner.forceUpdate(currentActionBar.placeholders(), Collections.emptySet());
|
||||
}
|
||||
textChangeFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onHeartBeatTimer() {
|
||||
if (textChangeFlag) {
|
||||
refresh();
|
||||
sendLatestActionBar();
|
||||
return;
|
||||
}
|
||||
if (shouldSendBeatPacket()) {
|
||||
sendLatestActionBar();
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
latestContent = this.currentActionBar.render(owner);
|
||||
textChangeFlag = false;
|
||||
}
|
||||
|
||||
public void sendLatestActionBar() {
|
||||
if (latestContent != null) {
|
||||
updateLastUpdateTime();
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().setActionBarTextPacket(AdventureHelper.miniMessageToMinecraftComponent(latestContent, "np", "ab"));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
this.owner.removeFeature(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> activePlaceholders() {
|
||||
if (currentActionBar == null) return Collections.emptySet();
|
||||
return currentActionBar.placeholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> allPlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
for (ActionBarConfig config : manager.allConfigs()) {
|
||||
for (CarouselText text : config.carouselTexts()) {
|
||||
placeholders.addAll(text.preParsedDynamicText().placeholders());
|
||||
}
|
||||
}
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPlaceholderUpdates(CNPlayer player, boolean force) {
|
||||
refresh();
|
||||
sendLatestActionBar();
|
||||
}
|
||||
|
||||
public void updateLastUpdateTime() {
|
||||
lastUpdateTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean shouldSendBeatPacket() {
|
||||
return System.currentTimeMillis() - lastUpdateTime > 1500;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String externalActionBar() {
|
||||
if (System.currentTimeMillis() > externalExpireTime) {
|
||||
externalActionBar = "";
|
||||
}
|
||||
return externalActionBar;
|
||||
}
|
||||
|
||||
public void externalActionBar(@NotNull String externalActionBar) {
|
||||
requireNonNull(externalActionBar);
|
||||
this.externalActionBar = externalActionBar;
|
||||
this.externalExpireTime = System.currentTimeMillis() + 3000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
public interface AdvanceManager extends Reloadable {
|
||||
|
||||
void loadTemplates();
|
||||
|
||||
ConfigurableFontAdvanceData getCustomFontData(String id);
|
||||
|
||||
CharacterFontAdvanceData getCharacterFontData(String id);
|
||||
|
||||
float getLineAdvance(String text);
|
||||
|
||||
float getCharAdvance(char[] chars, Key font, boolean bold);
|
||||
|
||||
int getLines(String text, int width);
|
||||
|
||||
List<Tuple<String, Key, Boolean>> miniMessageToIterable(String text);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
int size();
|
||||
|
||||
Float getAdvance(int codePoint);
|
||||
|
||||
Map<Integer, Float> data();
|
||||
|
||||
String id();
|
||||
|
||||
List<JsonObject> fontProvider(Map<String, Object> properties);
|
||||
|
||||
static Builder builder() {
|
||||
return new CharacterFontAdvanceDataImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder advance(Map<Integer, Float> data);
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder fontProviderFunction(Function<Map<String, Object>, List<JsonObject>> function);
|
||||
|
||||
CharacterFontAdvanceData build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
data.clear();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,32 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.paper.mechanic.requirement.papi;
|
||||
|
||||
import org.bukkit.OfflinePlayer;
|
||||
package net.momirealms.customnameplates.api.feature.advance;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ExpressionOr(List<PapiRequirement> requirements) implements PapiRequirement{
|
||||
public interface ConfigurableFontAdvanceData {
|
||||
|
||||
@Override
|
||||
public boolean isMet(OfflinePlayer player) {
|
||||
for (PapiRequirement requirement : requirements) {
|
||||
if (requirement.isMet(player)) return true;
|
||||
}
|
||||
return false;
|
||||
float defaultAdvance();
|
||||
|
||||
float getAdvance(int codePoint);
|
||||
|
||||
String id();
|
||||
|
||||
static Builder builder() {
|
||||
return new ConfigurableFontAdvanceDataImpl.BuilderImpl();
|
||||
}
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder defaultAdvance(float width);
|
||||
|
||||
Builder advance(int codePoint, float width);
|
||||
|
||||
Builder parentFont(List<CharacterFontAdvanceData> font);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,11 +15,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.paper.mechanic.bubble.image;
|
||||
package net.momirealms.customnameplates.api.feature.advance;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
public record SizeOverrides(int startCodePoint, int endCodePoint, int left, int right) {
|
||||
|
||||
public interface ImageParser {
|
||||
|
||||
String parse(Player player, String text);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface Background extends AdaptiveImage {
|
||||
|
||||
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();
|
||||
|
||||
static Builder builder() {
|
||||
return new BackgroundImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder left(ConfiguredCharacter character);
|
||||
|
||||
Builder width_1(ConfiguredCharacter character);
|
||||
|
||||
Builder width_2(ConfiguredCharacter character);
|
||||
|
||||
Builder width_4(ConfiguredCharacter character);
|
||||
|
||||
Builder width_8(ConfiguredCharacter character);
|
||||
|
||||
Builder width_16(ConfiguredCharacter character);
|
||||
|
||||
Builder width_32(ConfiguredCharacter character);
|
||||
|
||||
Builder width_64(ConfiguredCharacter character);
|
||||
|
||||
Builder width_128(ConfiguredCharacter character);
|
||||
|
||||
Builder right(ConfiguredCharacter character);
|
||||
|
||||
Background build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* 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 n, float leftMargin, float rightMargin) {
|
||||
String offset1 = OffsetFont.shortestNegChars(n + rightMargin + right.advance());
|
||||
n = leftMargin + n + rightMargin;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(left.character());
|
||||
while (n >= 128) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_128.character());
|
||||
n -= 128;
|
||||
}
|
||||
if (n - 64 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_64.character());
|
||||
n -= 64;
|
||||
}
|
||||
if (n - 32 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_32.character());
|
||||
n -= 32;
|
||||
}
|
||||
if (n - 16 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_16.character());
|
||||
n -= 16;
|
||||
}
|
||||
if (n - 8 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_8.character());
|
||||
n -= 8;
|
||||
}
|
||||
if (n - 4 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_4.character());
|
||||
n -= 4;
|
||||
}
|
||||
if (n - 2 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_2.character());
|
||||
n -= 2;
|
||||
}
|
||||
if (n - 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) {
|
||||
return OffsetFont.shortestPosChars(rightMargin + right.advance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createImage(float n, float leftMargin, float rightMargin) {
|
||||
n = n + leftMargin + rightMargin + 2;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(left.character());
|
||||
while (n >= 128) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_128.character());
|
||||
n -= 128;
|
||||
}
|
||||
if (n - 64 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_64.character());
|
||||
n -= 64;
|
||||
}
|
||||
if (n - 32 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_32.character());
|
||||
n -= 32;
|
||||
}
|
||||
if (n - 16 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_16.character());
|
||||
n -= 16;
|
||||
}
|
||||
if (n - 8 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_8.character());
|
||||
n -= 8;
|
||||
}
|
||||
if (n - 4 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_4.character());
|
||||
n -= 4;
|
||||
}
|
||||
if (n - 2 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_2.character());
|
||||
n -= 2;
|
||||
}
|
||||
if (n - 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.common.plugin.feature.Reloadable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface BackgroundManager extends Reloadable {
|
||||
|
||||
@Nullable
|
||||
Background getBackground(String id);
|
||||
|
||||
Collection<Background> getBackgrounds();
|
||||
}
|
||||
@@ -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.background;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class BackgroundManagerImpl implements BackgroundManager {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final Map<String, Background> backgrounds = new HashMap<>();
|
||||
|
||||
public BackgroundManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.backgrounds.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Background getBackground(String id) {
|
||||
return this.backgrounds.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Background> getBackgrounds() {
|
||||
return new HashSet<>(backgrounds.values());
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
File backgroundFolder = new File(plugin.getDataDirectory().toFile(), "contents" + File.separator + "backgrounds");
|
||||
if (!backgroundFolder.exists() && backgroundFolder.mkdirs()) {
|
||||
saveDefaultBackgrounds();
|
||||
}
|
||||
List<File> configFiles = ConfigUtils.getConfigsDeeply(backgroundFolder);
|
||||
for (File configFile : configFiles) {
|
||||
YamlDocument config = plugin.getConfigManager().loadData(configFile);
|
||||
String id = configFile.getName().substring(0, configFile.getName().lastIndexOf("."));
|
||||
int height = config.getInt("middle.height", 14);
|
||||
int ascent = config.getInt("middle.ascent", 8);
|
||||
Background background = Background.builder()
|
||||
.id(id)
|
||||
.left(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("left.image") + ".png"),
|
||||
config.getInt("left.ascent", 8),
|
||||
config.getInt("left.height", 14)
|
||||
))
|
||||
.right(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("right.image") + ".png"),
|
||||
config.getInt("right.ascent", 8),
|
||||
config.getInt("right.height", 14)
|
||||
))
|
||||
.width_1(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.1") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_2(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.2") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_4(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.4") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_8(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.8") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_16(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.16") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_32(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.32") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_64(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.64") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.width_128(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.128") + ".png"),
|
||||
ascent, height
|
||||
))
|
||||
.build();
|
||||
this.backgrounds.put(id, background);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDefaultBackgrounds() {
|
||||
String[] bg_list = new String[]{"b0", "b1", "b2", "b4", "b8", "b16","b32","b64","b128"};
|
||||
for (String bg : bg_list) {
|
||||
plugin.getConfigManager().saveResource("contents" + File.separator + "backgrounds" + File.separator + bg + ".png");
|
||||
}
|
||||
String[] config_list = new String[]{"bedrock_1", "bedrock_2"};
|
||||
for (String config : config_list) {
|
||||
plugin.getConfigManager().saveResource("contents" + File.separator + "backgrounds" + File.separator + config + ".yml");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,35 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.paper.storage.method.database.sql;
|
||||
package net.momirealms.customnameplates.api.feature.bossbar;
|
||||
|
||||
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
|
||||
import net.momirealms.customnameplates.api.data.StorageType;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MySQLImpl extends AbstractHikariDatabase {
|
||||
public interface BossBar {
|
||||
|
||||
public MySQLImpl(CustomNameplatesPlugin plugin) {
|
||||
super(plugin);
|
||||
UUID uuid();
|
||||
|
||||
float progress();
|
||||
|
||||
Color color();
|
||||
|
||||
Overlay overlay();
|
||||
|
||||
enum Overlay {
|
||||
PROGRESS,
|
||||
NOTCHED_6,
|
||||
NOTCHED_10,
|
||||
NOTCHED_12,
|
||||
NOTCHED_20
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageType getStorageType() {
|
||||
return StorageType.MySQL;
|
||||
enum Color {
|
||||
BLUE,
|
||||
GREEN,
|
||||
PINK,
|
||||
PURPLE,
|
||||
RED,
|
||||
WHITE,
|
||||
YELLOW
|
||||
}
|
||||
}
|
||||
@@ -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.bossbar;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
|
||||
public interface BossBarConfig {
|
||||
|
||||
BossBar.Overlay DEFAULT_OVERLAY = BossBar.Overlay.PROGRESS;
|
||||
BossBar.Color DEFAULT_COLOR = BossBar.Color.YELLOW;
|
||||
|
||||
String id();
|
||||
|
||||
Requirement[] requirements();
|
||||
|
||||
CarouselText[] carouselTexts();
|
||||
|
||||
BossBar.Overlay overlay();
|
||||
|
||||
BossBar.Color color();
|
||||
|
||||
float progress();
|
||||
|
||||
static BossBarConfig.Builder builder() {
|
||||
return new BossBarConfigImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder requirement(Requirement[] requirements);
|
||||
|
||||
Builder carouselText(CarouselText[] carouselTexts);
|
||||
|
||||
Builder overlay(BossBar.Overlay overlay);
|
||||
|
||||
Builder color(BossBar.Color color);
|
||||
|
||||
Builder progress(float progress);
|
||||
|
||||
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,87 @@
|
||||
/*
|
||||
* 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.CNPlayer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BossBarDisplayController {
|
||||
|
||||
private final CNPlayer owner;
|
||||
private final BossBarManager manager;
|
||||
private final BossBarSender[] senders;
|
||||
|
||||
public BossBarDisplayController(BossBarManager manager, CNPlayer owner) {
|
||||
this.owner = owner;
|
||||
this.manager = manager;
|
||||
List<BossBarSender> senderList = new ArrayList<>();
|
||||
for (BossBarConfig config : manager.allConfigs()) {
|
||||
BossBarSender sender = new BossBarSender(owner, config);
|
||||
senderList.add(sender);
|
||||
this.owner.addFeature(sender);
|
||||
}
|
||||
this.senders = senderList.toArray(new BossBarSender[0]);
|
||||
}
|
||||
|
||||
public void onTick() {
|
||||
int size = senders.length;
|
||||
int[] states = new int[size];
|
||||
int index = size;
|
||||
for (int i = 0; i < size; i++) {
|
||||
BossBarSender sender = senders[i];
|
||||
boolean canShow = sender.checkConditions();
|
||||
if (canShow) {
|
||||
if (!sender.isShown()) {
|
||||
states[i] = 1;
|
||||
sender.init();
|
||||
sender.tick();
|
||||
if (index == size) {
|
||||
index = i;
|
||||
}
|
||||
} else {
|
||||
states[i] = 2;
|
||||
if (i > index) {
|
||||
sender.hide();
|
||||
}
|
||||
sender.tick();
|
||||
}
|
||||
} else {
|
||||
if (sender.isShown()) {
|
||||
sender.hide();
|
||||
}
|
||||
states[i] = 0;
|
||||
}
|
||||
}
|
||||
if (index != size) {
|
||||
for (int i = index; i < size; i++) {
|
||||
if (states[i] != 0) {
|
||||
senders[i].show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
for (BossBarSender sender : this.senders) {
|
||||
sender.hide();
|
||||
this.owner.removeFeature(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
void onTick();
|
||||
|
||||
BossBarConfig getConfig(String name);
|
||||
|
||||
BossBarConfig[] allConfigs();
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.feature.JoinQuitListener;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BossBarManagerImpl implements BossBarManager, JoinQuitListener {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final LinkedHashMap<String, BossBarConfig> configs = new LinkedHashMap<>();
|
||||
private final ConcurrentHashMap<UUID, BossBarDisplayController> senders = new ConcurrentHashMap<>();
|
||||
private BossBarConfig[] configArray = new BossBarConfig[0];
|
||||
|
||||
public BossBarManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// ignore disabled modules
|
||||
if (!ConfigManager.bossbarModule()) return;
|
||||
this.loadConfig();
|
||||
this.resetArray();
|
||||
for (CNPlayer online : plugin.getOnlinePlayers()) {
|
||||
onPlayerJoin(online);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
for (BossBarDisplayController sender : senders.values()) {
|
||||
sender.destroy();
|
||||
}
|
||||
this.senders.clear();
|
||||
this.configs.clear();
|
||||
this.resetArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
for (BossBarDisplayController sender : senders.values()) {
|
||||
sender.onTick();
|
||||
}
|
||||
}
|
||||
|
||||
private void resetArray() {
|
||||
configArray = configs.values().toArray(new BossBarConfig[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerJoin(CNPlayer player) {
|
||||
if (!ConfigManager.bossbarModule()) return;
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
if (!player.isOnline()) return;
|
||||
BossBarDisplayController sender = new BossBarDisplayController(this, player);
|
||||
BossBarDisplayController previous = senders.put(player.uuid(), sender);
|
||||
if (previous != null) {
|
||||
previous.destroy();
|
||||
}
|
||||
}, ConfigManager.delaySend() * 50L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerQuit(CNPlayer player) {
|
||||
BossBarDisplayController sender = senders.remove(player.uuid());
|
||||
if (sender != null) {
|
||||
sender.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBarConfig getConfig(String name) {
|
||||
return configs.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBarConfig[] allConfigs() {
|
||||
return configArray;
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
plugin.getConfigManager().saveResource("configs" + File.separator + "bossbar.yml");
|
||||
YamlDocument document = plugin.getConfigManager().loadData(new File(plugin.getDataDirectory().toFile(), "configs" + File.separator + "bossbar.yml"));
|
||||
for (Map.Entry<String, Object> entry : document.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (!(entry.getValue() instanceof Section section))
|
||||
return;
|
||||
this.configs.put(entry.getKey(),
|
||||
BossBarConfig.builder()
|
||||
.id(entry.getKey())
|
||||
.overlay(BossBar.Overlay.valueOf(section.getString("overlay", "PROGRESS").toUpperCase(Locale.ENGLISH)))
|
||||
.color(BossBar.Color.valueOf(section.getString("color", "YELLOW").toUpperCase(Locale.ENGLISH)))
|
||||
.requirement(plugin.getRequirementManager().parseRequirements(section.getSection("conditions")))
|
||||
.carouselText(
|
||||
section.contains("text") ?
|
||||
new CarouselText[]{new CarouselText(-1, new Requirement[0], section.getString("text"), false)} :
|
||||
ConfigUtils.carouselTexts(section.getSection("text-display-order"))
|
||||
)
|
||||
.progress(section.getFloat("progress", 0f))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.feature.DynamicText;
|
||||
import net.momirealms.customnameplates.api.feature.Feature;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
import net.momirealms.customnameplates.api.placeholder.Placeholder;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BossBarSender implements Feature, BossBar {
|
||||
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final CNPlayer owner;
|
||||
|
||||
private boolean isShown = false;
|
||||
private final BossBarConfig config;
|
||||
|
||||
private int order;
|
||||
private int timeLeft;
|
||||
private DynamicText currentBossBar;
|
||||
|
||||
private String latestContent;
|
||||
|
||||
public BossBarSender(CNPlayer owner, BossBarConfig config) {
|
||||
this.owner = owner;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BossBarSender that = (BossBarSender) o;
|
||||
return owner == that.owner && uuid == that.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return uuid.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID uuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "BossBarSender";
|
||||
}
|
||||
|
||||
@Override
|
||||
public float progress() {
|
||||
return config.progress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color color() {
|
||||
return config.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Overlay overlay() {
|
||||
return config.overlay();
|
||||
}
|
||||
|
||||
public boolean checkConditions() {
|
||||
return owner.isMet(config.requirements());
|
||||
}
|
||||
|
||||
public void init() {
|
||||
order = config.carouselTexts().length - 1;
|
||||
timeLeft = 0;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if (timeLeft > 0)
|
||||
timeLeft--;
|
||||
|
||||
if (timeLeft == 0) {
|
||||
int triedTimes = 0;
|
||||
|
||||
do {
|
||||
if (triedTimes == config.carouselTexts().length) {
|
||||
timeLeft = 20;
|
||||
currentBossBar = null;
|
||||
CustomNameplates.getInstance().getPluginLogger().warn("No text in order is available for player " + owner.name() + ". Please check your bossbar's conditions.");
|
||||
return;
|
||||
}
|
||||
order++;
|
||||
if (order >= config.carouselTexts().length) {
|
||||
order = 0;
|
||||
}
|
||||
triedTimes++;
|
||||
} while (
|
||||
!owner.isMet(config.carouselTexts()[order].requirements())
|
||||
);
|
||||
|
||||
CarouselText carouselText = config.carouselTexts()[order];
|
||||
timeLeft = carouselText.duration();
|
||||
currentBossBar = carouselText.preParsedDynamicText().fastCreate(owner);
|
||||
|
||||
if (carouselText.updateOnDisplay()) {
|
||||
owner.forceUpdate(currentBossBar.placeholders(), Collections.emptySet());
|
||||
}
|
||||
|
||||
refresh();
|
||||
if (isShown()) {
|
||||
sendLatestBossBarName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
isShown = false;
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().removeBossBarPacket(uuid);
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
isShown = true;
|
||||
if (latestContent == null) {
|
||||
refresh();
|
||||
}
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().createBossBarPacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(latestContent), progress(), overlay(), color());
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
}
|
||||
|
||||
public boolean isShown() {
|
||||
return isShown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> activePlaceholders() {
|
||||
if (currentBossBar == null || !isShown()) return Collections.emptySet();
|
||||
return currentBossBar.placeholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> allPlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
for (CarouselText text : config.carouselTexts()) {
|
||||
placeholders.addAll(text.preParsedDynamicText().placeholders());
|
||||
}
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPlaceholderUpdates(CNPlayer p1, boolean force) {
|
||||
refresh();
|
||||
if (isShown()) {
|
||||
sendLatestBossBarName();
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
latestContent = this.currentBossBar.render(owner);
|
||||
}
|
||||
|
||||
public void sendLatestBossBarName() {
|
||||
if (latestContent != null) {
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateBossBarNamePacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(latestContent));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.bubble;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
|
||||
public interface Bubble extends AdaptiveImage {
|
||||
|
||||
String id();
|
||||
|
||||
ConfiguredCharacter left();
|
||||
|
||||
ConfiguredCharacter right();
|
||||
|
||||
ConfiguredCharacter middle();
|
||||
|
||||
ConfiguredCharacter tail();
|
||||
|
||||
static Builder builder() {
|
||||
return new BubbleImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder left(ConfiguredCharacter left);
|
||||
|
||||
Builder right(ConfiguredCharacter right);
|
||||
|
||||
Builder middle(ConfiguredCharacter middle);
|
||||
|
||||
Builder tail(ConfiguredCharacter tail);
|
||||
|
||||
Bubble build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
String id();
|
||||
|
||||
int backgroundColor();
|
||||
|
||||
int lineWidth();
|
||||
|
||||
int maxLines();
|
||||
|
||||
Bubble[] bubbles();
|
||||
|
||||
String textPrefix();
|
||||
|
||||
String textSuffix();
|
||||
|
||||
String displayName();
|
||||
|
||||
Vector3 scale();
|
||||
|
||||
static Builder builder() {
|
||||
return new BubbleConfigImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder displayName(String displayName);
|
||||
|
||||
Builder backgroundColor(int backgroundColor);
|
||||
|
||||
Builder lineWidth(int lineWidth);
|
||||
|
||||
Builder maxLines(int maxLines);
|
||||
|
||||
Builder bubbles(Bubble[] bubbles);
|
||||
|
||||
Builder textPrefix(String textPrefix);
|
||||
|
||||
Builder textSuffix(String textSuffix);
|
||||
|
||||
Builder scale(Vector3 scale);
|
||||
|
||||
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,192 @@
|
||||
/*
|
||||
* 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) {
|
||||
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) {
|
||||
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) {
|
||||
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,64 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
Collection<BubbleConfig> getBubbleConfigs();
|
||||
|
||||
@Nullable
|
||||
Bubble getBubble(String id);
|
||||
|
||||
@Nullable BubbleConfig getBubbleConfig(String id);
|
||||
|
||||
Collection<Bubble> getBubbles();
|
||||
|
||||
boolean hasBubble(CNPlayer player, String id);
|
||||
|
||||
Collection<BubbleConfig> availableBubbles(CNPlayer player);
|
||||
|
||||
Set<String> blacklistChannels();
|
||||
|
||||
String defaultBubbleId();
|
||||
|
||||
Requirement[] sendBubbleRequirements();
|
||||
|
||||
Requirement[] viewBubbleRequirements();
|
||||
|
||||
String omittedText();
|
||||
|
||||
double verticalOffset();
|
||||
|
||||
int stayDuration();
|
||||
|
||||
int appearDuration();
|
||||
|
||||
int disappearDuration();
|
||||
|
||||
float viewRange();
|
||||
|
||||
ChannelMode channelMode();
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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 dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.ChatListener;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TagRenderer;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final Map<String, Bubble> bubbles = new HashMap<>();
|
||||
private Requirement[] sendBubbleRequirements;
|
||||
private Requirement[] viewBubbleRequirements;
|
||||
private String defaultBubbleId;
|
||||
private String omittedText;
|
||||
private double yOffset;
|
||||
private int stayDuration;
|
||||
private int appearDuration;
|
||||
private int disappearDuration;
|
||||
private float viewRange;
|
||||
private Set<String> blacklistChannels;
|
||||
private ChannelMode channelMode;
|
||||
private final HashMap<String, BubbleConfig> bubbleConfigs = new HashMap<>();
|
||||
|
||||
public BubbleManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.bubbles.clear();
|
||||
this.bubbleConfigs.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (!ConfigManager.bubbleModule()) return;
|
||||
this.loadConfigs();
|
||||
this.loadConfig();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Bubble getBubble(String id) {
|
||||
return this.bubbles.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BubbleConfig getBubbleConfig(String id) {
|
||||
return this.bubbleConfigs.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Bubble> getBubbles() {
|
||||
return new HashSet<>(bubbles.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BubbleConfig> getBubbleConfigs() {
|
||||
return new HashSet<>(bubbleConfigs.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBubble(CNPlayer player, String id) {
|
||||
if (!this.bubbleConfigs.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
return player.hasPermission("bubbles.equip." + id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BubbleConfig> availableBubbles(CNPlayer player) {
|
||||
ArrayList<BubbleConfig> available = new ArrayList<>();
|
||||
for (BubbleConfig bubble : bubbleConfigs.values()) {
|
||||
if (player.hasPermission("bubbles.equip." + bubble.id())) {
|
||||
available.add(bubble);
|
||||
}
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> blacklistChannels() {
|
||||
return blacklistChannels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultBubbleId() {
|
||||
return defaultBubbleId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] sendBubbleRequirements() {
|
||||
return sendBubbleRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] viewBubbleRequirements() {
|
||||
return viewBubbleRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String omittedText() {
|
||||
return omittedText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double verticalOffset() {
|
||||
return yOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int stayDuration() {
|
||||
return stayDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int appearDuration() {
|
||||
return appearDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int disappearDuration() {
|
||||
return disappearDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float viewRange() {
|
||||
return viewRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelMode channelMode() {
|
||||
return channelMode;
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
plugin.getConfigManager().saveResource("configs" + File.separator + "bubble.yml");
|
||||
YamlDocument document = plugin.getConfigManager().loadData(new File(plugin.getDataDirectory().toFile(), "configs" + File.separator + "bubble.yml"));
|
||||
sendBubbleRequirements = plugin.getRequirementManager().parseRequirements(document.getSection("sender-requirements"));
|
||||
viewBubbleRequirements = plugin.getRequirementManager().parseRequirements(document.getSection("viewer-requirements"));
|
||||
defaultBubbleId = document.getString("default-bubble", "chat");
|
||||
omittedText = document.getString("omitted-text", "...");
|
||||
yOffset = document.getDouble("y-offset", 0.2);
|
||||
stayDuration = document.getInt("stay-duration", 160);
|
||||
appearDuration = document.getInt("appear-duration", 20);
|
||||
disappearDuration = document.getInt("disappear-duration", 10);
|
||||
viewRange = document.getFloat("view-range", 0.5f);
|
||||
blacklistChannels = new HashSet<>(document.getStringList("blacklist-channels"));
|
||||
channelMode = ChannelMode.valueOf(document.getString("channel-mode", "ALL").toUpperCase(Locale.ENGLISH));
|
||||
Section bubbleSettings = document.getSection("bubble-settings");
|
||||
if (bubbleSettings != null) {
|
||||
for (Map.Entry<String, Object> entry : bubbleSettings.getStringRouteMappedValues(false).entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
int maxLines = inner.getInt("max-lines", 1);
|
||||
Bubble[] bubbleArray = new Bubble[maxLines];
|
||||
for (int i = 0; i < maxLines; i++) {
|
||||
bubbleArray[i] = getBubble(inner.getString("lines." + (i+1)));
|
||||
}
|
||||
this.bubbleConfigs.put(key, BubbleConfig.builder()
|
||||
.id(key)
|
||||
.maxLines(maxLines)
|
||||
.bubbles(bubbleArray)
|
||||
.displayName(inner.getString("display-name", key))
|
||||
.lineWidth(inner.getInt("line-width", 100))
|
||||
.backgroundColor(ConfigUtils.argb(inner.getString("background-color", "0,0,0,0")))
|
||||
.textPrefix(inner.getString("text-prefix", ""))
|
||||
.textSuffix(inner.getString("text-suffix", ""))
|
||||
.scale(ConfigUtils.vector3(inner.getString("scale", "1,1,1")))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
File bubbleFolder = new File(plugin.getDataDirectory().toFile(), "contents" + File.separator + "bubbles");
|
||||
if (!bubbleFolder.exists() && bubbleFolder.mkdirs()) {
|
||||
saveDefaultBubbles();
|
||||
}
|
||||
List<File> configFiles = ConfigUtils.getConfigsDeeply(bubbleFolder);
|
||||
for (File configFile : configFiles) {
|
||||
YamlDocument config = plugin.getConfigManager().loadData(configFile);
|
||||
String id = configFile.getName().substring(0, configFile.getName().lastIndexOf("."));
|
||||
Bubble bubble = Bubble.builder()
|
||||
.id(id)
|
||||
.left(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("left.image") + ".png"),
|
||||
config.getInt("left.ascent", 12),
|
||||
config.getInt("left.height", 16)
|
||||
))
|
||||
.middle(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.image") + ".png"),
|
||||
config.getInt("middle.ascent", 12),
|
||||
config.getInt("middle.height", 16)
|
||||
))
|
||||
.tail(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("tail.image") + ".png"),
|
||||
config.getInt("tail.ascent", 12),
|
||||
config.getInt("tail.height", 16)
|
||||
))
|
||||
.right(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("right.image") + ".png"),
|
||||
config.getInt("right.ascent", 12),
|
||||
config.getInt("right.height", 16)
|
||||
))
|
||||
.build();
|
||||
this.bubbles.put(id, bubble);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDefaultBubbles() {
|
||||
String[] png_list = new String[]{"chat_1", "chat_2", "chat_3"};
|
||||
String[] part_list = new String[]{"_left.png", "_middle.png", "_right.png", "_tail.png", ".yml"};
|
||||
for (String name : png_list) {
|
||||
for (String part : part_list) {
|
||||
plugin.getConfigManager().saveResource("contents" + File.separator + "bubbles" + File.separatorChar + name + part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerChat(CNPlayer player, String message, String channel) {
|
||||
if (!ConfigManager.bubbleModule()) return;
|
||||
// ignore blacklist channels
|
||||
if (blacklistChannels().contains(channel)) return;
|
||||
// check requirements
|
||||
if (!player.isMet(sendBubbleRequirements())) return;
|
||||
|
||||
String equippedBubble = player.equippedBubble();
|
||||
if (equippedBubble.equals("none")) equippedBubble = defaultBubbleId;
|
||||
|
||||
BubbleConfig config = bubbleConfigs.get(equippedBubble);
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fullText = config.textPrefix() + AdventureHelper.stripTags(message.replace("\\", "\\\\")) + config.textSuffix();
|
||||
int lines = plugin.getAdvanceManager().getLines(fullText, config.lineWidth());
|
||||
if (lines > config.maxLines()) return;
|
||||
|
||||
TagRenderer renderer = plugin.getUnlimitedTagManager().getTagRender(player);
|
||||
if (renderer == null) return;
|
||||
int removed = renderer.removeTagIf(tag -> tag.id().equals("bubble"));
|
||||
int delay = 0;
|
||||
if (removed != 0) {
|
||||
delay += disappearDuration;
|
||||
}
|
||||
|
||||
Bubble bubble = config.bubbles()[lines - 1];
|
||||
float advance;
|
||||
if (lines == 1) {
|
||||
advance = plugin.getAdvanceManager().getLineAdvance(fullText);
|
||||
} else {
|
||||
advance = config.lineWidth();
|
||||
}
|
||||
|
||||
BubbleTag bubbleTagText = new BubbleTag(player, renderer, channel, config,
|
||||
AdventureHelper.miniMessageToMinecraftComponent(fullText),
|
||||
bubble == null ? null : AdventureHelper.miniMessageToMinecraftComponent(AdventureHelper.surroundWithNameplatesFont(bubble.createImage(advance, 1,1))), this);
|
||||
renderer.addTag(bubbleTagText);
|
||||
if (delay != 0) {
|
||||
plugin.getScheduler().asyncLater(() -> bubbleTagText.setCanShow(true), delay * 50L, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
bubbleTagText.setCanShow(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.tag.AbstractTag;
|
||||
import net.momirealms.customnameplates.api.feature.tag.Tag;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TagRenderer;
|
||||
import net.momirealms.customnameplates.api.network.Tracker;
|
||||
import net.momirealms.customnameplates.api.util.Alignment;
|
||||
import net.momirealms.customnameplates.api.util.SelfIncreaseEntityID;
|
||||
import net.momirealms.customnameplates.api.util.Vector3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BubbleTag extends AbstractTag {
|
||||
|
||||
private final Object text;
|
||||
@Nullable
|
||||
private final Object background;
|
||||
private final BubbleManager manager;
|
||||
private final BubbleConfig bubbleConfig;
|
||||
private int ticker;
|
||||
private boolean canShow;
|
||||
private final String channel;
|
||||
private final HashMap<UUID, Boolean> cachedVisibility = new HashMap<>();
|
||||
|
||||
protected final int subEntityID = SelfIncreaseEntityID.getAndIncrease();
|
||||
protected final UUID subEntityUUID = UUID.randomUUID();
|
||||
|
||||
public BubbleTag(CNPlayer owner, TagRenderer renderer, String channel, BubbleConfig bubbleConfig, Object text, @Nullable Object background, BubbleManager bubbleManager) {
|
||||
super(owner, renderer);
|
||||
this.text = text;
|
||||
this.manager = bubbleManager;
|
||||
this.bubbleConfig = bubbleConfig;
|
||||
this.channel = channel;
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> spawnPacket(CNPlayer viewer) {
|
||||
Tracker tracker = owner.getTracker(viewer);
|
||||
Vector3 translation = translation(viewer);
|
||||
List<Object> packets = new ArrayList<>(CustomNameplates.getInstance().getPlatform().createTextDisplayPacket(
|
||||
entityID, uuid,
|
||||
owner.position().add(0, (1.8 + (affectedByCrouching() && tracker.isCrouching() && !owner.isFlying() ? -0.3 : 0) + renderer.hatOffset()) * (affectedByScaling() ? tracker.getScale() : 1), 0),
|
||||
0f, 0f, 0d,
|
||||
-1, 0, 0,
|
||||
text, bubbleConfig.backgroundColor(), (byte) -1, false, false, false,
|
||||
Alignment.CENTER, manager.viewRange(), 0.0f, 1.0f,
|
||||
new Vector3(0.001, 0.001, 0.001),
|
||||
affectedByScaling() ? translation.add(0.001, -manager.verticalOffset(), 0.001).multiply(tracker.getScale()) : translation.add(0.001, -manager.verticalOffset(), 0.001),
|
||||
bubbleConfig.lineWidth(),
|
||||
(affectedByCrouching() && tracker.isCrouching())
|
||||
));
|
||||
if (background != null) {
|
||||
packets.addAll(CustomNameplates.getInstance().getPlatform().createTextDisplayPacket(
|
||||
subEntityID, subEntityUUID,
|
||||
owner.position().add(0,(1.8 + (affectedByCrouching() && tracker.isCrouching() && !owner.isFlying() ? -0.3 : 0) + renderer.hatOffset()) * (affectedByScaling() ? tracker.getScale() : 1),0),
|
||||
0f, 0f, 0d,
|
||||
-1, 0, 0,
|
||||
background, 0, (byte) -1, false, false, false,
|
||||
Alignment.CENTER, manager.viewRange(), 0.0f, 1.0f,
|
||||
new Vector3(0.001, 0.001, 0.001),
|
||||
affectedByScaling() ? translation.add(0, -manager.verticalOffset(), 0).multiply(tracker.getScale()) : translation.add(0, -manager.verticalOffset(), 0),
|
||||
2048,
|
||||
(affectedByCrouching() && tracker.isCrouching())
|
||||
));
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
public void setCanShow(boolean canShow) {
|
||||
this.canShow = canShow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShow() {
|
||||
return canShow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShow(CNPlayer viewer) {
|
||||
if (!viewer.isMet(owner, manager.viewBubbleRequirements())) {
|
||||
return false;
|
||||
}
|
||||
switch (manager.channelMode()) {
|
||||
case ALL -> {
|
||||
return true;
|
||||
}
|
||||
case JOINED -> {
|
||||
Boolean previous = cachedVisibility.get(viewer.uuid());
|
||||
if (previous != null) return previous;
|
||||
boolean can = CustomNameplates.getInstance().getChatManager().chatProvider().hasJoinedChannel(viewer, channel);
|
||||
cachedVisibility.put(viewer.uuid(), can);
|
||||
return can;
|
||||
}
|
||||
case CAN_JOIN -> {
|
||||
Boolean previous = cachedVisibility.get(viewer.uuid());
|
||||
if (previous != null) return previous;
|
||||
boolean can = CustomNameplates.getInstance().getChatManager().chatProvider().canJoinChannel(viewer, channel);
|
||||
cachedVisibility.put(viewer.uuid(), can);
|
||||
return can;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(CNPlayer viewer) {
|
||||
if (!isShown()) return;
|
||||
viewers.add(viewer);
|
||||
resetViewerArray();
|
||||
owner.trackPassengers(viewer, entityID);
|
||||
if (background != null)
|
||||
owner.trackPassengers(viewer, subEntityID);
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, spawnPacket(viewer));
|
||||
CustomNameplates.getInstance().getScheduler().asyncLater(() -> {
|
||||
Consumer<List<Object>> modifier0 = CustomNameplates.getInstance().getPlatform().createInterpolationDelayModifier(-1);
|
||||
Consumer<List<Object>> modifier1 = CustomNameplates.getInstance().getPlatform().createTransformationInterpolationDurationModifier(manager.appearDuration());
|
||||
Consumer<List<Object>> modifier2 = CustomNameplates.getInstance().getPlatform().createScaleModifier(bubbleConfig.scale());
|
||||
Consumer<List<Object>> modifier3 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(viewer));
|
||||
Object packet1 = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier0, modifier1, modifier2, modifier3));
|
||||
if (background != null) {
|
||||
Object packet2 = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(subEntityID, List.of(modifier0, modifier1, modifier2, modifier3));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, List.of(packet1, packet2));
|
||||
} else {
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet1);
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (!canShow) return;
|
||||
if (ticker >= manager.stayDuration()) {
|
||||
renderer.removeTag(this);
|
||||
return;
|
||||
}
|
||||
ticker++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (!isShown()) return;
|
||||
|
||||
CNPlayer[] viewers = viewerArray.clone();
|
||||
CustomNameplates.getInstance().getScheduler().asyncLater(() -> {
|
||||
Object removePacket = createRemovePacket();
|
||||
for (CNPlayer viewer : viewers) {
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, removePacket);
|
||||
}
|
||||
}, manager.disappearDuration() * 50L, TimeUnit.MILLISECONDS);
|
||||
|
||||
List<Object> disappearPacket = createDisappearPacket();
|
||||
for (CNPlayer viewer : viewers) {
|
||||
if (background != null) {
|
||||
owner.untrackPassengers(viewer, entityID, subEntityID);
|
||||
} else {
|
||||
owner.untrackPassengers(viewer, entityID);
|
||||
}
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, disappearPacket);
|
||||
}
|
||||
|
||||
this.cachedVisibility.clear();
|
||||
this.isShown = false;
|
||||
this.viewers.clear();
|
||||
resetViewerArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(CNPlayer viewer) {
|
||||
if (!isShown()) return;
|
||||
viewers.remove(viewer);
|
||||
resetViewerArray();
|
||||
if (background != null) {
|
||||
owner.untrackPassengers(viewer, entityID, subEntityID);
|
||||
} else {
|
||||
owner.untrackPassengers(viewer, entityID);
|
||||
}
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, createDisappearPacket());
|
||||
}
|
||||
|
||||
private Object createRemovePacket() {
|
||||
Object packet;
|
||||
if (background != null) {
|
||||
packet = CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID, subEntityID);
|
||||
} else {
|
||||
packet = CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
private List<Object> createDisappearPacket() {
|
||||
Consumer<List<Object>> modifier0 = CustomNameplates.getInstance().getPlatform().createInterpolationDelayModifier(-1);
|
||||
Consumer<List<Object>> modifier1 = CustomNameplates.getInstance().getPlatform().createTransformationInterpolationDurationModifier(manager.disappearDuration());
|
||||
Consumer<List<Object>> modifier2 = CustomNameplates.getInstance().getPlatform().createScaleModifier(new Vector3(0.001,0.001,0.001));
|
||||
if (background != null) {
|
||||
return List.of(CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier0, modifier1, modifier2)), CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(subEntityID, List.of(modifier0, modifier1, modifier2)));
|
||||
} else {
|
||||
return List.of(CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier0, modifier1, modifier2)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTextHeight(CNPlayer viewer) {
|
||||
return -Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 scale(CNPlayer viewer) {
|
||||
return new Vector3(1,1,1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 translation(CNPlayer viewer) {
|
||||
return new Vector3(0, manager.verticalOffset() + maxY(viewer), 0);
|
||||
}
|
||||
|
||||
public double maxY(CNPlayer viewer) {
|
||||
double y = 0;
|
||||
for (Tag tag : renderer.tags()) {
|
||||
if (tag.isShown() && tag.isShown(viewer) && !tag.id().equals(id())) {
|
||||
double currentY = tag.translation(viewer).y() + tag.getTextHeight(viewer);
|
||||
if (currentY > y) {
|
||||
y = currentY;
|
||||
}
|
||||
}
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return "bubble";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByCrouching() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByScaling() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.api.mechanic.bubble;
|
||||
package net.momirealms.customnameplates.api.feature.bubble;
|
||||
|
||||
public enum ChannelMode {
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.chat;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.ChatListener;
|
||||
import net.momirealms.customnameplates.api.feature.bubble.emoji.EmojiProvider;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractChatManager implements ChatManager {
|
||||
|
||||
protected final CustomNameplates plugin;
|
||||
protected final List<EmojiProvider> emojiProviders = new ArrayList<>();
|
||||
protected final List<ChatListener> listeners = new ArrayList<>();
|
||||
protected ChatMessageProvider chatProvider;
|
||||
protected ChatMessageProvider customProvider;
|
||||
|
||||
public AbstractChatManager(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.emojiProviders.clear();
|
||||
if (chatProvider instanceof AbstractChatMessageProvider chatMessageProvider) {
|
||||
chatMessageProvider.unregister();
|
||||
}
|
||||
chatProvider = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
setUpPlatformEmojiProviders();
|
||||
if (customProvider == null) {
|
||||
setUpPlatformProvider();
|
||||
} else {
|
||||
chatProvider = customProvider;
|
||||
}
|
||||
if (chatProvider instanceof AbstractChatMessageProvider chatMessageProvider) {
|
||||
chatMessageProvider.register();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void setUpPlatformProvider();
|
||||
|
||||
protected abstract void setUpPlatformEmojiProviders();
|
||||
|
||||
@Override
|
||||
public boolean setCustomChatProvider(ChatMessageProvider provider) {
|
||||
if (this.customProvider != null)
|
||||
return false;
|
||||
this.customProvider = provider;
|
||||
this.reload();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCustomChatProvider() {
|
||||
if (this.customProvider != null) {
|
||||
this.customProvider = null;
|
||||
this.reload();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
unload();
|
||||
this.listeners.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(final ChatListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(final ChatListener listener) {
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatMessageProvider chatProvider() {
|
||||
return chatProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChat(CNPlayer player, String message, String channel) {
|
||||
String text = message;
|
||||
for (EmojiProvider provider : emojiProviders) {
|
||||
text = provider.replace(player, text);
|
||||
}
|
||||
text = AdventureHelper.legacyToMiniMessage(text);
|
||||
for (ChatListener listener : listeners) {
|
||||
listener.onPlayerChat(player, text, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,23 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.common.team;
|
||||
package net.momirealms.customnameplates.api.feature.bubble.chat;
|
||||
|
||||
import java.util.Locale;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
|
||||
public enum TeamColor {
|
||||
public abstract class AbstractChatMessageProvider implements ChatMessageProvider {
|
||||
|
||||
BLACK,
|
||||
DARK_BLUE,
|
||||
DARK_GREEN,
|
||||
DARK_AQUA,
|
||||
DARK_RED,
|
||||
DARK_PURPLE,
|
||||
GOLD,
|
||||
GRAY,
|
||||
DARK_GRAY,
|
||||
BLUE,
|
||||
GREEN,
|
||||
AQUA,
|
||||
RED,
|
||||
LIGHT_PURPLE,
|
||||
YELLOW,
|
||||
WHITE,
|
||||
NONE,
|
||||
CUSTOM;
|
||||
protected CustomNameplates plugin;
|
||||
protected ChatManager manager;
|
||||
|
||||
public TeamColor getById(String id) throws IllegalArgumentException {
|
||||
return valueOf(id.toUpperCase(Locale.ENGLISH));
|
||||
public AbstractChatMessageProvider(CustomNameplates plugin, ChatManager manager) {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
}
|
||||
}
|
||||
@@ -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.feature.bubble.chat;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.feature.ChatListener;
|
||||
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
|
||||
|
||||
public interface ChatManager extends Reloadable {
|
||||
|
||||
boolean setCustomChatProvider(ChatMessageProvider provider);
|
||||
|
||||
boolean removeCustomChatProvider();
|
||||
|
||||
void registerListener(ChatListener listener);
|
||||
|
||||
void unregisterListener(ChatListener listener);
|
||||
|
||||
ChatMessageProvider chatProvider();
|
||||
|
||||
void onChat(CNPlayer player, String message, String channel);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.chat;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
|
||||
public interface ChatMessageProvider {
|
||||
|
||||
boolean hasJoinedChannel(CNPlayer player, String channelID);
|
||||
|
||||
boolean canJoinChannel(CNPlayer player, String channelID);
|
||||
|
||||
boolean isIgnoring(CNPlayer sender, CNPlayer receiver);
|
||||
}
|
||||
@@ -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,11 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.paper.mechanic.requirement.papi;
|
||||
package net.momirealms.customnameplates.api.feature.bubble.emoji;
|
||||
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
|
||||
public interface PapiRequirement {
|
||||
public interface EmojiProvider {
|
||||
|
||||
boolean isMet(OfflinePlayer player);
|
||||
String replace(CNPlayer player, String text);
|
||||
}
|
||||
@@ -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,28 +15,34 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.api.mechanic.tag.unlimited;
|
||||
package net.momirealms.customnameplates.api.feature.image;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
|
||||
import java.util.Collection;
|
||||
public interface Image {
|
||||
|
||||
public interface EntityTagEntity {
|
||||
String id();
|
||||
|
||||
void addTag(StaticTextEntity tag);
|
||||
boolean hasShadow();
|
||||
|
||||
StaticTextEntity addTag(StaticTextTagSetting setting);
|
||||
int opacity();
|
||||
|
||||
void removeTag(StaticTextEntity tag);
|
||||
ConfiguredCharacter character();
|
||||
|
||||
Collection<StaticTextEntity> getStaticTags();
|
||||
static Builder builder() {
|
||||
return new ImageImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
void forceAddNearbyPlayer(Player player);
|
||||
interface Builder {
|
||||
|
||||
void forceRemoveNearbyPlayer(Player player);
|
||||
Builder id(String id);
|
||||
|
||||
Entity getEntity();
|
||||
Builder hasShadow(boolean has);
|
||||
|
||||
void destroy();
|
||||
Builder opacity(int opacity);
|
||||
|
||||
Builder character(ConfiguredCharacter character);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.common.plugin.feature.Reloadable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ImageManager extends Reloadable {
|
||||
|
||||
@Nullable
|
||||
Image getImage(String id);
|
||||
|
||||
Collection<Image> getImages();
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class ImageManagerImpl implements ImageManager {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final HashMap<String, Image> images = new HashMap<>();
|
||||
|
||||
public ImageManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.images.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Image getImage(String id) {
|
||||
return images.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Image> getImages() {
|
||||
return new HashSet<>(images.values());
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
File imageFolder = new File(plugin.getDataDirectory().toFile(), "contents" + File.separator + "images");
|
||||
if (!imageFolder.exists() && imageFolder.mkdirs()) {
|
||||
saveDefaultImages();
|
||||
}
|
||||
List<File> configFiles = ConfigUtils.getConfigsDeeply(imageFolder);
|
||||
for (File configFile : configFiles) {
|
||||
YamlDocument config = plugin.getConfigManager().loadData(configFile);
|
||||
String id = configFile.getName().substring(0, configFile.getName().lastIndexOf("."));
|
||||
Image image = Image.builder()
|
||||
.id(id)
|
||||
.hasShadow(!config.getBoolean("shadow.remove", false))
|
||||
.opacity(config.getInt("shadow.opacity", 254))
|
||||
.character(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("image") + ".png"),
|
||||
config.getInt("ascent", 8),
|
||||
config.getInt("height", 10)
|
||||
))
|
||||
.build();
|
||||
this.images.put(id, image);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDefaultImages() {
|
||||
String[] png_list = new String[]{"bell", "bubble", "clock", "coin", "compass", "weather", "stamina_0", "stamina_1", "stamina_2"};
|
||||
String[] part_list = new String[]{".png", ".yml"};
|
||||
for (String name : png_list) {
|
||||
for (String part : part_list) {
|
||||
plugin.getConfigManager().saveResource("contents" + File.separator + "images" + File.separator + name + part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.nameplate;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
|
||||
public interface Nameplate extends AdaptiveImage {
|
||||
|
||||
String id();
|
||||
|
||||
String displayName();
|
||||
|
||||
ConfiguredCharacter left();
|
||||
|
||||
ConfiguredCharacter middle();
|
||||
|
||||
ConfiguredCharacter right();
|
||||
|
||||
static Builder builder() {
|
||||
return new NameplateImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder displayName(String displayName);
|
||||
|
||||
Builder left(ConfiguredCharacter left);
|
||||
|
||||
Builder middle(ConfiguredCharacter middle);
|
||||
|
||||
Builder right(ConfiguredCharacter right);
|
||||
|
||||
Nameplate build();
|
||||
}
|
||||
}
|
||||
@@ -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.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) {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,26 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.velocity.team;
|
||||
package net.momirealms.customnameplates.api.feature.nameplate;
|
||||
|
||||
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.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface VelocityTeamManager {
|
||||
import java.util.Collection;
|
||||
|
||||
public interface NameplateManager extends Reloadable {
|
||||
|
||||
@Nullable
|
||||
String getTeam(Player player, Player viewer);
|
||||
Nameplate getNameplate(String id);
|
||||
|
||||
void sendTeamUpdatePacket(Player receiver, String team, TeamColor color, TeamTagVisibility visibility, Component prefix, Component suffix);
|
||||
Collection<Nameplate> getNameplates();
|
||||
|
||||
boolean hasNameplate(CNPlayer player, String id);
|
||||
|
||||
Collection<Nameplate> availableNameplates(CNPlayer player);
|
||||
|
||||
String defaultNameplateId();
|
||||
|
||||
String playerNameTag();
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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 dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import net.momirealms.customnameplates.api.feature.DynamicText;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class NameplateManagerImpl implements NameplateManager {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final Map<String, Nameplate> nameplates = new HashMap<>();
|
||||
private final Map<UUID, DynamicText> tags = new HashMap<>();
|
||||
private String defaultNameplateId;
|
||||
private String nameTag;
|
||||
|
||||
public NameplateManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.nameplates.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadConfig();
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Nameplate getNameplate(String id) {
|
||||
return this.nameplates.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Nameplate> getNameplates() {
|
||||
return new HashSet<>(nameplates.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNameplate(CNPlayer player, String id) {
|
||||
if (!this.nameplates.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
return player.hasPermission("nameplates.equip." + id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Nameplate> availableNameplates(CNPlayer player) {
|
||||
ArrayList<Nameplate> available = new ArrayList<>();
|
||||
for (Nameplate nameplate : nameplates.values()) {
|
||||
if (player.hasPermission("nameplates.equip." + nameplate.id())) {
|
||||
available.add(nameplate);
|
||||
}
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultNameplateId() {
|
||||
return defaultNameplateId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String playerNameTag() {
|
||||
return nameTag;
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
plugin.getConfigManager().saveResource("configs" + File.separator + "nameplate.yml");
|
||||
YamlDocument document = plugin.getConfigManager().loadData(new File(plugin.getDataDirectory().toFile(), "configs" + File.separator + "nameplate.yml"));
|
||||
defaultNameplateId = document.getString("default-nameplate", "none");
|
||||
String prefix = document.getString("nameplate.prefix", "");
|
||||
String name = document.getString("nameplate.player-name", "%player_name%");
|
||||
String suffix = document.getString("nameplate.suffix", "");
|
||||
nameTag = prefix + name + suffix;
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
File nameplateFolder = new File(plugin.getDataDirectory().toFile(), "contents" + File.separator + "nameplates");
|
||||
if (!nameplateFolder.exists() && nameplateFolder.mkdirs()) {
|
||||
saveDefaultNameplates();
|
||||
}
|
||||
List<File> configFiles = ConfigUtils.getConfigsDeeply(nameplateFolder);
|
||||
for (File configFile : configFiles) {
|
||||
YamlDocument config = plugin.getConfigManager().loadData(configFile);
|
||||
String id = configFile.getName().substring(0, configFile.getName().lastIndexOf("."));
|
||||
Nameplate nameplate = Nameplate.builder()
|
||||
.id(id)
|
||||
.displayName(config.getString("display-name", id))
|
||||
.left(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("left.image") + ".png"),
|
||||
config.getInt("left.ascent", 12),
|
||||
config.getInt("left.height", 16)
|
||||
))
|
||||
.middle(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("middle.image") + ".png"),
|
||||
config.getInt("middle.ascent", 12),
|
||||
config.getInt("middle.height", 16)
|
||||
))
|
||||
.right(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("right.image") + ".png"),
|
||||
config.getInt("right.ascent", 12),
|
||||
config.getInt("right.height", 16)
|
||||
))
|
||||
.build();
|
||||
this.nameplates.put(id, nameplate);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDefaultNameplates() {
|
||||
String[] png_list = new String[]{"cat", "egg", "cheems", "wither", "xmas", "halloween", "hutao", "starsky", "trident", "rabbit"};
|
||||
String[] part_list = new String[]{"_left.png", "_middle.png", "_right.png", ".yml"};
|
||||
for (String name : png_list) {
|
||||
for (String part : part_list) {
|
||||
plugin.getConfigManager().saveResource("contents" + File.separator + "nameplates" + File.separator + name + part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* 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.pack;
|
||||
|
||||
public class CharacterArranger {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.pack;
|
||||
|
||||
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
|
||||
|
||||
public interface ResourcePackManager extends Reloadable {
|
||||
|
||||
void generate();
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* 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.pack;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import net.momirealms.customnameplates.api.feature.OffsetFont;
|
||||
import net.momirealms.customnameplates.api.feature.advance.CharacterFontAdvanceData;
|
||||
import net.momirealms.customnameplates.api.feature.background.Background;
|
||||
import net.momirealms.customnameplates.api.feature.bubble.Bubble;
|
||||
import net.momirealms.customnameplates.api.feature.image.Image;
|
||||
import net.momirealms.customnameplates.api.feature.nameplate.Nameplate;
|
||||
import net.momirealms.customnameplates.api.helper.VersionHelper;
|
||||
import net.momirealms.customnameplates.api.util.CharacterUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
|
||||
public ResourcePackManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate() {
|
||||
File resourcePackFolder = new File(plugin.getDataFolder() + File.separator + "ResourcePack");
|
||||
// delete the old one
|
||||
this.deleteDirectory(resourcePackFolder);
|
||||
|
||||
// create folders
|
||||
File fontFolder = new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "assets" + File.separator + ConfigManager.namespace() + File.separatorChar + "font");
|
||||
File texturesFolder = new File(plugin.getDataFolder(), "ResourcePack" + File.separator+ "assets" + File.separator + ConfigManager.namespace() + File.separatorChar + "textures");
|
||||
if (!fontFolder.mkdirs() || !texturesFolder.mkdirs()) {
|
||||
plugin.getPluginLogger().severe("Failed to generate resource pack folders");
|
||||
return;
|
||||
}
|
||||
|
||||
// save BossBars
|
||||
this.saveBossBar();
|
||||
// save unicodes
|
||||
this.saveLegacyUnicodes();
|
||||
|
||||
if (!VersionHelper.isVersionNewerThan1_20_5()) {
|
||||
this.generateShaders("ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, false);
|
||||
this.generateShaders("ResourcePack" + File.separator + "overlay_1_20_5" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true);
|
||||
} else {
|
||||
this.generateShaders("ResourcePack" + File.separator + "overlay_1_20_5" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true);
|
||||
try {
|
||||
FileUtils.copyDirectory(
|
||||
new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_20_5"),
|
||||
new File(plugin.getDataFolder(), "ResourcePack")
|
||||
);
|
||||
FileUtils.deleteDirectory(new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_20_5"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// create json object
|
||||
JsonObject fontJson = new JsonObject();
|
||||
JsonArray providers = new JsonArray();
|
||||
fontJson.add("providers", providers);
|
||||
// add offset characters
|
||||
this.getOffsets(texturesFolder).forEach(providers::add);
|
||||
// add nameplate characters
|
||||
this.getNameplates(texturesFolder).forEach(providers::add);
|
||||
// add bubble characters
|
||||
this.getBubbles(texturesFolder).forEach(providers::add);
|
||||
// add background characters
|
||||
this.getBackgrounds(texturesFolder).forEach(providers::add);
|
||||
// add image characters
|
||||
this.getImages(texturesFolder).forEach(providers::add);
|
||||
// save json object to file
|
||||
this.saveFont(fontJson);
|
||||
// generate shift fonts
|
||||
this.generateFont();
|
||||
// set pack.mcmeta/pack.png
|
||||
this.setPackFormat();
|
||||
// copy the resource pack to hooked plugins
|
||||
this.copyResourcePackToHookedPlugins(resourcePackFolder);
|
||||
}
|
||||
|
||||
private void saveFont(JsonObject fontJson) {
|
||||
try (FileWriter fileWriter = new FileWriter(
|
||||
plugin.getDataFolder() +
|
||||
File.separator + "ResourcePack" +
|
||||
File.separator + "assets" +
|
||||
File.separator + ConfigManager.namespace() +
|
||||
File.separator + "font" +
|
||||
File.separator + ConfigManager.font() + ".json")
|
||||
) {
|
||||
fileWriter.write(fontJson.toString().replace("\\\\", "\\"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFont() {
|
||||
YamlDocument document = ConfigManager.getMainConfig();
|
||||
Section section = document.getSection("other-settings.shift-fonts");
|
||||
if (section != null) {
|
||||
for (Object key : section.getKeys()) {
|
||||
if (key instanceof String font) {
|
||||
JsonObject jo = new JsonObject();
|
||||
JsonArray providers = new JsonArray();
|
||||
jo.add("providers", providers);
|
||||
List<String> order = section.getStringList(font);
|
||||
for (String f : order) {
|
||||
String[] split = f.split(":", 2);
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
if (split.length == 2) {
|
||||
properties.put("shift_y", Integer.parseInt(split[1]));
|
||||
}
|
||||
CharacterFontAdvanceData data = plugin.getAdvanceManager().getCharacterFontData(split[0]);
|
||||
if (data == null) {
|
||||
plugin.getPluginLogger().warn("Font template [" + split[0] + "] not found");
|
||||
continue;
|
||||
}
|
||||
List<JsonObject> jsonObject = data.fontProvider(properties);
|
||||
if (jsonObject == null) {
|
||||
plugin.getPluginLogger().warn("Font template [" + split[0] + "] doesn't support shift");
|
||||
continue;
|
||||
}
|
||||
for (JsonObject o : jsonObject) {
|
||||
providers.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
try (FileWriter file = new FileWriter(new File(plugin.getDataFolder(),
|
||||
"ResourcePack" +
|
||||
File.separator + "assets" +
|
||||
File.separator + ConfigManager.namespace() +
|
||||
File.separator + "font" +
|
||||
File.separator + font + ".json"))) {
|
||||
file.write(jo.toString().replace("\\\\", "\\"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private void setPackFormat() {
|
||||
if (VersionHelper.isVersionNewerThan1_20_5()) {
|
||||
plugin.getConfigManager().saveResource("ResourcePack" + File.separator + "pack_1_20_5.mcmeta");
|
||||
File file = new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "pack_1_20_5.mcmeta");
|
||||
file.renameTo(new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "pack.mcmeta"));
|
||||
} else {
|
||||
plugin.getConfigManager().saveResource("ResourcePack" + File.separator + "pack.mcmeta");
|
||||
}
|
||||
plugin.getConfigManager().saveResource("ResourcePack" + File.separator + "pack.png");
|
||||
}
|
||||
|
||||
private void copyResourcePackToHookedPlugins(File resourcePackFolder) {
|
||||
File pluginsFolder = plugin.getDataFolder().getParentFile();
|
||||
if (ConfigManager.packItemsAdder()) {
|
||||
File file = new File(pluginsFolder, "ItemsAdder" + File.separator + "config.yml");
|
||||
YamlDocument iaConfig = plugin.getConfigManager().loadData(file);
|
||||
List<String> folders = iaConfig.getStringList("resource-pack.zip.merge_other_plugins_resourcepacks_folders");
|
||||
boolean changed = false;
|
||||
if (!folders.contains("CustomNameplates/ResourcePack")) {
|
||||
folders.add("CustomNameplates/ResourcePack");
|
||||
iaConfig.set("resource-pack.zip.merge_other_plugins_resourcepacks_folders", folders);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
try {
|
||||
iaConfig.save(file);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ConfigManager.packItemsAdderLegacy()){
|
||||
try {
|
||||
FileUtils.copyDirectory(new File(resourcePackFolder, "assets"), new File(pluginsFolder, "ItemsAdder" + File.separator + "contents" + File.separator + "nameplates" + File.separator + "resourcepack" + File.separator + "assets") );
|
||||
} catch (IOException e){
|
||||
plugin.getPluginLogger().warn("Failed to copy files to ItemsAdder", e);
|
||||
}
|
||||
}
|
||||
if (ConfigManager.packOraxen()){
|
||||
try {
|
||||
FileUtils.copyDirectory(new File(resourcePackFolder, "assets"), new File(pluginsFolder, "Oraxen" + File.separator + "pack" + File.separator + "assets"));
|
||||
} catch (IOException e){
|
||||
plugin.getPluginLogger().warn("Failed to copy files to Oraxen", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<JsonObject> getBubbles(File texturesFolder) {
|
||||
ArrayList<JsonObject> list = new ArrayList<>();
|
||||
if (!ConfigManager.bubbleModule()) return list;
|
||||
for (Bubble bubble : plugin.getBubbleManager().getBubbles()) {
|
||||
for (ConfiguredCharacter configuredChar : new ConfiguredCharacter[]{bubble.left(), bubble.middle(), bubble.right(), bubble.tail()}) {
|
||||
JsonObject jo = new JsonObject();
|
||||
jo.add("type", new JsonPrimitive("bitmap"));
|
||||
jo.add("file", new JsonPrimitive(ConfigManager.namespace() + ":" + ConfigManager.bubblePath().replace("\\", "/") + configuredChar.imageFile().getName()));
|
||||
jo.add("ascent", new JsonPrimitive(configuredChar.ascent()));
|
||||
jo.add("height", new JsonPrimitive(configuredChar.height()));
|
||||
JsonArray ja = new JsonArray();
|
||||
ja.add(CharacterUtils.char2Unicode(configuredChar.character()));
|
||||
jo.add("chars", ja);
|
||||
list.add(jo);
|
||||
try {
|
||||
FileUtils.copyFile(
|
||||
new File(plugin.getDataFolder(),
|
||||
"contents" + File.separator + "bubbles" + File.separator + configuredChar.imageFile().getName()),
|
||||
new File(texturesFolder,
|
||||
ConfigManager.bubblePath().replace("\\", File.separator) + configuredChar.imageFile().getName()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<JsonObject> getBackgrounds(File texturesFolder) {
|
||||
ArrayList<JsonObject> list = new ArrayList<>();
|
||||
if (!ConfigManager.backgroundModule()) return list;
|
||||
for (Background backGround : plugin.getBackgroundManager().getBackgrounds()) {
|
||||
for (ConfiguredCharacter configuredChar : new ConfiguredCharacter[]{
|
||||
backGround.left(), backGround.width_1(),
|
||||
backGround.width_2(), backGround.width_4(),
|
||||
backGround.width_8(), backGround.width_16(),
|
||||
backGround.width_32(), backGround.width_64(),
|
||||
backGround.width_128(), backGround.right()}
|
||||
) {
|
||||
JsonObject jo = new JsonObject();
|
||||
jo.add("type", new JsonPrimitive("bitmap"));
|
||||
jo.add("file", new JsonPrimitive(ConfigManager.namespace() + ":" + ConfigManager.backgroundPath().replace("\\", "/") + configuredChar.imageFile().getName()));
|
||||
jo.add("ascent", new JsonPrimitive(configuredChar.ascent()));
|
||||
jo.add("height", new JsonPrimitive(configuredChar.height()));
|
||||
JsonArray ja = new JsonArray();
|
||||
ja.add(CharacterUtils.char2Unicode(configuredChar.character()));
|
||||
jo.add("chars", ja);
|
||||
list.add(jo);
|
||||
try {
|
||||
FileUtils.copyFile(
|
||||
new File(plugin.getDataFolder(),
|
||||
"contents" + File.separator + "backgrounds" + File.separator + configuredChar.imageFile().getName()),
|
||||
new File(texturesFolder,
|
||||
ConfigManager.backgroundPath().replace("\\", File.separator) + configuredChar.imageFile().getName()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<JsonObject> getImages(File texturesFolder) {
|
||||
ArrayList<JsonObject> list = new ArrayList<>();
|
||||
if (!ConfigManager.imageModule()) return list;
|
||||
for (Image image : plugin.getImageManager().getImages()) {
|
||||
ConfiguredCharacter character = image.character();
|
||||
JsonObject jo = new JsonObject();
|
||||
jo.add("type", new JsonPrimitive("bitmap"));
|
||||
jo.add("file", new JsonPrimitive(ConfigManager.namespace() + ":" + ConfigManager.imagePath().replace("\\", "/") + character.imageFile().getName()));
|
||||
jo.add("ascent", new JsonPrimitive(character.ascent()));
|
||||
jo.add("height", new JsonPrimitive(character.height()));
|
||||
JsonArray ja = new JsonArray();
|
||||
ja.add(CharacterUtils.char2Unicode(character.character()));
|
||||
jo.add("chars", ja);
|
||||
list.add(jo);
|
||||
try {
|
||||
FileUtils.copyFile(
|
||||
new File(plugin.getDataFolder(),
|
||||
"contents" + File.separator + "images" + File.separator + character.imageFile().getName()),
|
||||
new File(texturesFolder,
|
||||
ConfigManager.imagePath().replace("\\", File.separator) + character.imageFile().getName()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<JsonObject> getNameplates(File texturesFolder) {
|
||||
ArrayList<JsonObject> list = new ArrayList<>();
|
||||
if (!ConfigManager.nameplateModule()) return list;
|
||||
for (Nameplate nameplate : plugin.getNameplateManager().getNameplates()) {
|
||||
for (ConfiguredCharacter configuredChar : new ConfiguredCharacter[]{nameplate.left(), nameplate.middle(), nameplate.right()}) {
|
||||
JsonObject jo = new JsonObject();
|
||||
jo.add("type", new JsonPrimitive("bitmap"));
|
||||
jo.add("file", new JsonPrimitive(ConfigManager.namespace() + ":" + ConfigManager.nameplatePath().replace("\\", "/") + configuredChar.imageFile().getName()));
|
||||
jo.add("ascent", new JsonPrimitive(configuredChar.ascent()));
|
||||
jo.add("height", new JsonPrimitive(configuredChar.height()));
|
||||
JsonArray ja = new JsonArray();
|
||||
ja.add(CharacterUtils.char2Unicode(configuredChar.character()));
|
||||
jo.add("chars", ja);
|
||||
list.add(jo);
|
||||
try {
|
||||
FileUtils.copyFile(
|
||||
new File(plugin.getDataFolder(),
|
||||
"contents" + File.separator + "nameplates" + File.separator + configuredChar.imageFile().getName()),
|
||||
new File(texturesFolder,
|
||||
ConfigManager.nameplatePath().replace("\\", File.separator) + configuredChar.imageFile().getName()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<JsonObject> getOffsets(File texturesFolder) {
|
||||
this.saveSplit(texturesFolder);
|
||||
ArrayList<JsonObject> list = new ArrayList<>();
|
||||
for (OffsetFont offsetFont : OffsetFont.values()) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.add("type", new JsonPrimitive("bitmap"));
|
||||
jsonObject.add("file", new JsonPrimitive(ConfigManager.namespace() + ":" + ConfigManager.spaceSplitPath().replace("\\","/") + "space_split.png"));
|
||||
jsonObject.add("ascent", new JsonPrimitive(-5000));
|
||||
jsonObject.add("height", new JsonPrimitive(offsetFont.height()));
|
||||
final JsonArray jsonArray = new JsonArray();
|
||||
jsonArray.add(CharacterUtils.char2Unicode(offsetFont.character()));
|
||||
jsonObject.add("chars", jsonArray);
|
||||
list.add(jsonObject);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private void saveSplit(File texturesFolder) {
|
||||
try {
|
||||
plugin.getConfigManager().saveResource("space_split.png");
|
||||
FileUtils.copyFile(new File(plugin.getDataFolder(),"space_split.png"), new File(texturesFolder, ConfigManager.spaceSplitPath().replace("\\", File.separator) + "space_split.png"));
|
||||
File file = new File(plugin.getDataFolder(),"space_split.png");
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
} catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void deleteDirectory(File file){
|
||||
if (file.exists()) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(file);
|
||||
} catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveBossBar() {
|
||||
if (ConfigManager.bossBar1_20_2()) {
|
||||
String color = ConfigManager.removedBarColor().name().toLowerCase(Locale.ENGLISH);
|
||||
String path = "ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "textures" + File.separator + "gui" + File.separator + "sprites" + File.separator + "boss_bar" + File.separator;
|
||||
plugin.getConfigManager().saveResource(path + color + "_background.png");
|
||||
plugin.getConfigManager().saveResource(path + color + "_progress.png");
|
||||
}
|
||||
if (ConfigManager.bossBar1_17()) {
|
||||
String path = "ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "textures" + File.separator + "gui" + File.separator + "bars.png";
|
||||
plugin.getConfigManager().saveResource(path);
|
||||
try {
|
||||
File inputFile = new File(plugin.getDataFolder(), path);
|
||||
BufferedImage image = ImageIO.read(inputFile);
|
||||
int y;
|
||||
switch (ConfigManager.removedBarColor()) {
|
||||
case PINK -> y = 0;
|
||||
case BLUE -> y = 10;
|
||||
case RED -> y = 20;
|
||||
case GREEN -> y = 30;
|
||||
case PURPLE -> y = 50;
|
||||
case WHITE -> y = 60;
|
||||
default -> y = 40;
|
||||
}
|
||||
int width = 182;
|
||||
int height = 10;
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = y; j < y + height; j++) {
|
||||
image.setRGB(i, j, 0);
|
||||
}
|
||||
}
|
||||
ImageIO.write(image, "png", inputFile);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveLegacyUnicodes() {
|
||||
if (ConfigManager.legacyUnicodes()) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
var path = "font" + File.separator + "unicode_page_" + String.format("%02x", i) + ".png";
|
||||
var destination = "ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "textures" + File.separator + "font" + File.separator + "unicode_page_" + String.format("%02x", i) + ".png";
|
||||
File imageFile = new File(plugin.getDataFolder(), path);
|
||||
File destinationFile = new File(plugin.getDataFolder(), destination);
|
||||
if (imageFile.exists()) {
|
||||
try {
|
||||
FileUtils.copyFile(imageFile, destinationFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateShaders(String path, boolean v1_20_5) {
|
||||
if (!ConfigManager.enableShader()) return;
|
||||
|
||||
plugin.getConfigManager().saveResource(path + "rendertype_text.fsh");
|
||||
plugin.getConfigManager().saveResource(path + "rendertype_text.json");
|
||||
plugin.getConfigManager().saveResource(path + "rendertype_text.vsh");
|
||||
|
||||
String line;
|
||||
StringBuilder sb1 = new StringBuilder();
|
||||
File shader1 = new File(plugin.getDataFolder(), path + "rendertype_text.vsh");
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(shader1), StandardCharsets.UTF_8))) {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb1.append(line).append(System.lineSeparator());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String mainShader = v1_20_5 ? ShaderConstants.Nameplates_Shader_1_20_5 : ShaderConstants.Nameplates_Shader_1_20_4;
|
||||
try (BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(shader1), StandardCharsets.UTF_8))) {
|
||||
writer.write(sb1.toString()
|
||||
.replace("%SHADER_0%", !ConfigManager.animatedText() ? "" : ShaderConstants.Animated_Text_Out)
|
||||
.replace("%SHADER_1%", !ConfigManager.itemsAdderEffect() ? mainShader : ShaderConstants.ItemsAdder_Text_Effects + mainShader)
|
||||
.replace("%SHADER_2%", !ConfigManager.animatedText() ? "" : ShaderConstants.Animated_Text_VSH)
|
||||
.replace("%SHADER_3%", !ConfigManager.hideScoreBoardNumber() ? "" : ShaderConstants.Hide_ScoreBoard_Numbers)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
File shader2 = new File(plugin.getDataFolder(), path + "rendertype_text.fsh");
|
||||
StringBuilder sb2 = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(shader2), StandardCharsets.UTF_8))) {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
sb2.append(line).append(System.lineSeparator());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try (BufferedWriter writer = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(shader2), StandardCharsets.UTF_8))) {
|
||||
writer.write(sb2.toString()
|
||||
.replace("%SHADER_0%", !ConfigManager.animatedText() ? "" : ShaderConstants.Animated_Text_In)
|
||||
.replace("%SHADER_1%", !ConfigManager.animatedText() ? "" : ShaderConstants.Animated_Text_FSH)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ShaderConstants {
|
||||
|
||||
public static final String Nameplates_Shader_1_20_5 =
|
||||
"if (Color.xyz == vec3(255., 254., 253.) / 255.) {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.y += 1;\n" +
|
||||
" vertex.x += 1;\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else if (Color.xyz == vec3(254., 254., 254.) / 255.) {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.z *= 1.001;\n" +
|
||||
" vertex.x *= 1.001;\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else if (Color.xyz == vec3(253., 254., 254.) / 255.) {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.z *= 1.001001;\n" +
|
||||
" vertex.x *= 1.001001;\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" }";
|
||||
|
||||
public static final String Nameplates_Shader_1_20_4 =
|
||||
"if (Color.xyz == vec3(255., 254., 253.) / 255.) {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.y += 1;\n" +
|
||||
" vertex.x += 1;\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else if (Color.xyz == vec3(254., 254., 254.) / 255.) {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.z -= 0.001;\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else if (Color.xyz == vec3(253., 254., 254.) / 255.) {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.z -= 0.0011;\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else {\n" +
|
||||
" vertexColor = Color*texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" }";
|
||||
|
||||
public static final String ItemsAdder_Text_Effects =
|
||||
"if (Color.xyz == vec3(255., 255., 254.) / 255.) {\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" vertexColor = ((.6 + .6 * cos(6. * (gl_Position.x + GameTime * 1000.) + vec4(0, 23, 21, 1))) + vec4(0., 0., 0., 1.)) * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" } else if (Color.xyz == vec3(255., 255., 253.) / 255.) {\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" vertexColor = Color * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" gl_Position.y = gl_Position.y + sin(GameTime * 12000. + (gl_Position.x * 6)) / 150.;\n" +
|
||||
" } else if (Color.xyz == vec3(255., 255., 252.) / 255.) {\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" vertexColor = ((.6 + .6 * cos(6. * (gl_Position.x + GameTime * 1000.) + vec4(0, 23, 21, 1))) + vec4(0., 0., 0., 1.)) * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" gl_Position.y = gl_Position.y + sin(GameTime*12000. + (gl_Position.x*6)) / 150.;\n" +
|
||||
" } else if (Color.xyz == vec3(255., 255., 251.) / 255.) {\n" +
|
||||
" vertexColor = Color * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" float vertexId = mod(gl_VertexID, 4.0);\n" +
|
||||
" if (vertex.z <= 0.) {\n" +
|
||||
" if (vertexId == 3. || vertexId == 0.) vertex.y += cos(GameTime * 12000. / 4) * 0.1;\n" +
|
||||
" vertex.y += max(cos(GameTime*12000. / 4) * 0.1, 0.);\n" +
|
||||
" } else {\n" +
|
||||
" if (vertexId == 3. || vertexId == 0.) vertex.y -= cos(GameTime * 12000. / 4) * 3;\n" +
|
||||
" vertex.y -= max(cos(GameTime*12000. / 4) * 4, 0.);\n" +
|
||||
" }\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else if (Color.xyz == vec3(255., 254., 254.) / 255.) {\n" +
|
||||
" float vertexId = mod(gl_VertexID, 4.0);\n" +
|
||||
" if (vertex.z <= 0.) {\n" +
|
||||
" if (vertexId == 3. || vertexId == 0.) vertex.y += cos(GameTime * 12000. / 4) * 0.1;\n" +
|
||||
" vertex.y += max(cos(GameTime*12000. / 4) * 0.1, 0.);\n" +
|
||||
" } else {\n" +
|
||||
" if (vertexId == 3. || vertexId == 0.) vertex.y -= cos(GameTime * 12000. / 4) * 3;\n" +
|
||||
" vertex.y -= max(cos(GameTime*12000. / 4) * 4, 0.);\n" +
|
||||
" }\n" +
|
||||
" vertexColor = ((.6 + .6 * cos(6. * (gl_Position.x + GameTime * 1000.) + vec4(0, 23, 21, 1))) + vec4(0., 0., 0., 1.)) * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vertex;\n" +
|
||||
" } else ";
|
||||
public static final String Hide_ScoreBoard_Numbers =
|
||||
"\n" +
|
||||
" if (Position.z == 0.0\n" +
|
||||
" && gl_Position.x >= 0.94\n" +
|
||||
" && gl_Position.y >= -0.35\n" +
|
||||
" && vertexColor.g == 84.0/255.0\n" +
|
||||
" && vertexColor.g == 84.0/255.0\n" +
|
||||
" && vertexColor.r == 252.0/255.0\n" +
|
||||
" && gl_VertexID <= 7\n" +
|
||||
" ) {\n" +
|
||||
" gl_Position = ProjMat * ModelViewMat * vec4(ScreenSize + 100.0, 0.0, ScreenSize + 100.0);\n" +
|
||||
" }";
|
||||
|
||||
public static final String Animated_Text_FSH =
|
||||
"\n" +
|
||||
" vec2 p1 = round(pos1 / (posID == 0 ? 1 - coord.x : 1 - coord.y));\n" +
|
||||
" vec2 p2 = round(pos2 / (posID == 0 ? coord.y : coord.x));\n" +
|
||||
" ivec2 resolution = ivec2(abs(p1 - p2));\n" +
|
||||
" ivec2 corner = ivec2(min(p1, p2));\n" +
|
||||
" vec4 pixel = texture(Sampler0, corner / 256.0) * 255;\n" +
|
||||
" if (pixel.a == 1) {\n" +
|
||||
" ivec2 frames = ivec2(resolution / pixel.gb);\n" +
|
||||
" vec2 uv = (texCoord0 * 256 - corner) / frames.x;\n" +
|
||||
" if (uv.x > pixel.y || uv.y > pixel.z)\n" +
|
||||
" discard;\n" +
|
||||
" int time = int(GameTime * pixel.r * 10 * pixel.x) % int(frames.x * frames.y);\n" +
|
||||
" uv = corner + mod(uv, pixel.yz) + vec2(time % frames.x, time / frames.x % frames.y) * pixel.yz;\n" +
|
||||
" color = texture(Sampler0, uv / 256.0) * vertexColor * ColorModulator;\n" +
|
||||
" }";
|
||||
|
||||
public static final String Animated_Text_VSH =
|
||||
"\n" +
|
||||
" pos1 = pos2 = vec2(0);\n" +
|
||||
" posID = gl_VertexID % 4;\n" +
|
||||
" const vec2[4] corners = vec2[4](vec2(0), vec2(0, 1), vec2(1), vec2(1, 0));\n" +
|
||||
" coord = corners[posID];\n" +
|
||||
" if (posID == 0) pos1 = UV0 * 256;\n" +
|
||||
" if (posID == 2) pos2 = UV0 * 256;";
|
||||
|
||||
public static final String Animated_Text_Out =
|
||||
"\n" +
|
||||
"out vec2 pos1;\n" +
|
||||
"out vec2 pos2;\n" +
|
||||
"out vec2 coord;\n" +
|
||||
"flat out int posID;\n";
|
||||
|
||||
public static final String Animated_Text_In =
|
||||
"\n" +
|
||||
"in vec2 pos1;\n" +
|
||||
"in vec2 pos2;\n" +
|
||||
"in vec2 coord;\n" +
|
||||
"flat in int posID;\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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;
|
||||
viewers.remove(viewer);
|
||||
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 updateOpacity(byte opacity) {
|
||||
for (CNPlayer viewer : viewerArray) {
|
||||
updateOpacity(viewer, opacity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOpacity(CNPlayer viewer, byte opacity) {
|
||||
Consumer<List<Object>> modifiers = CustomNameplates.getInstance().getPlatform().createOpacityModifier(opacity);
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifiers));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScale(double scale) {
|
||||
for (CNPlayer viewer : viewerArray) {
|
||||
updateScale(viewer, scale);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScale(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) {
|
||||
Tracker tracker = owner.getTracker(player);
|
||||
if (tracker != null) {
|
||||
Consumer<List<Object>> modifier = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(player).multiply(tracker.getScale()));
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(player, 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,211 @@
|
||||
/*
|
||||
* 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.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.feature.DynamicText;
|
||||
import net.momirealms.customnameplates.api.feature.RelationalFeature;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
import net.momirealms.customnameplates.api.network.Tracker;
|
||||
import net.momirealms.customnameplates.api.placeholder.Placeholder;
|
||||
import net.momirealms.customnameplates.api.util.Vector3;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
|
||||
private final NameTagConfig config;
|
||||
private int order;
|
||||
private int timeLeft;
|
||||
private DynamicText currentText;
|
||||
|
||||
public NameTag(CNPlayer owner, NameTagConfig config, TagRenderer renderer) {
|
||||
super(owner, renderer);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
order = config.carouselTexts().length - 1;
|
||||
timeLeft = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> spawnPacket(CNPlayer viewer) {
|
||||
String newName = currentText.render(viewer);
|
||||
Object component = AdventureHelper.miniMessageToMinecraftComponent(newName);
|
||||
Tracker tracker = owner.getTracker(viewer);
|
||||
return CustomNameplates.getInstance().getPlatform().createTextDisplayPacket(
|
||||
entityID, uuid,
|
||||
owner.position().add(0,(1.8 + (affectedByCrouching() && tracker.isCrouching() && !owner.isFlying() ? -0.3 : 0) + renderer.hatOffset()) * (affectedByScaling() ? tracker.getScale() : 1),0),
|
||||
0f, 0f, 0d,
|
||||
0, 0, 0,
|
||||
component, config.backgroundColor(), config.opacity(), config.hasShadow(), config.isSeeThrough(), config.useDefaultBackgroundColor(),
|
||||
config.alignment(), config.viewRange(), config.shadowRadius(), config.shadowStrength(),
|
||||
(affectedByScaling() ? scale(viewer).multiply(tracker.getScale()) : scale(viewer)),
|
||||
(affectedByScaling() ? translation(viewer).multiply(tracker.getScale()) : translation(viewer)),
|
||||
config.lineWidth(),
|
||||
(affectedByCrouching() && tracker.isCrouching())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (timeLeft > 0)
|
||||
timeLeft--;
|
||||
|
||||
if (timeLeft == 0) {
|
||||
int triedTimes = 0;
|
||||
|
||||
do {
|
||||
if (triedTimes == config.carouselTexts().length) {
|
||||
timeLeft = 20;
|
||||
currentText = null;
|
||||
CustomNameplates.getInstance().getPluginLogger().warn("No text in order is available for player " + owner.name() + ". Please check your tag's conditions.");
|
||||
return;
|
||||
}
|
||||
order++;
|
||||
if (order >= config.carouselTexts().length) {
|
||||
order = 0;
|
||||
}
|
||||
triedTimes++;
|
||||
} while (
|
||||
!owner.isMet(config.carouselTexts()[order].requirements())
|
||||
);
|
||||
|
||||
CarouselText carouselText = config.carouselTexts()[order];
|
||||
timeLeft = carouselText.duration();
|
||||
currentText = carouselText.preParsedDynamicText().fastCreate(owner);
|
||||
|
||||
if (carouselText.updateOnDisplay()) {
|
||||
owner.forceUpdate(currentText.placeholders(), owner.nearbyPlayers());
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPlaceholderUpdates(CNPlayer p1, CNPlayer p2, boolean force) {
|
||||
refresh(p2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPlaceholderUpdates(CNPlayer p1, boolean force) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShow() {
|
||||
return owner.isMet(config.ownerRequirements());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShow(CNPlayer viewer) {
|
||||
return viewer.isMet(owner, config.viewerRequirements());
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
for (CNPlayer viewer : viewerArray) {
|
||||
refresh(viewer);
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh(CNPlayer viewer) {
|
||||
String newName = currentText.render(viewer);
|
||||
Object component = AdventureHelper.miniMessageToMinecraftComponent(newName);
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(CustomNameplates.getInstance().getPlatform().createTextComponentModifier(component)));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTextHeight(CNPlayer viewer) {
|
||||
String current = currentText.render(viewer);
|
||||
Tracker tracker = viewer.getTracker(owner);
|
||||
int lines = CustomNameplates.getInstance().getAdvanceManager().getLines(current, config.lineWidth());
|
||||
return ((lines * (9+1) + config.translation().y()) * config.scale().y() * (config.affectedByScaling() ? tracker.getScale() : 1)) / 40;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (!isShown()) return;
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID);
|
||||
for (CNPlayer viewer : viewerArray) {
|
||||
owner.untrackPassengers(viewer, entityID);
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
|
||||
}
|
||||
this.isShown = false;
|
||||
this.viewers.clear();
|
||||
resetViewerArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 scale(CNPlayer viewer) {
|
||||
return config.scale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 translation(CNPlayer viewer) {
|
||||
return config.translation().add(0, renderer.hatOffset(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "UnlimitedTag";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> activePlaceholders() {
|
||||
if (currentText == null || !isShown()) return Collections.emptySet();
|
||||
return currentText.placeholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> allPlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
for (CarouselText text : config.carouselTexts()) {
|
||||
placeholders.addAll(text.preParsedDynamicText().placeholders());
|
||||
}
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte opacity() {
|
||||
return config.opacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return "nametag";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByCrouching() {
|
||||
return config.affectedByScaling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByScaling() {
|
||||
return affectedByCrouching();
|
||||
}
|
||||
}
|
||||
@@ -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.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 {
|
||||
|
||||
String id();
|
||||
|
||||
Requirement[] ownerRequirements();
|
||||
|
||||
Requirement[] viewerRequirements();
|
||||
|
||||
CarouselText[] carouselTexts();
|
||||
|
||||
byte opacity();
|
||||
|
||||
int backgroundColor();
|
||||
|
||||
boolean hasShadow();
|
||||
|
||||
boolean isSeeThrough();
|
||||
|
||||
boolean useDefaultBackgroundColor();
|
||||
|
||||
boolean affectedByCrouching();
|
||||
|
||||
boolean affectedByScaling();
|
||||
|
||||
Alignment alignment();
|
||||
|
||||
float viewRange();
|
||||
|
||||
float shadowRadius();
|
||||
|
||||
float shadowStrength();
|
||||
|
||||
Vector3 scale();
|
||||
|
||||
Vector3 translation();
|
||||
|
||||
int lineWidth();
|
||||
|
||||
static Builder builder() {
|
||||
return new NameTagConfigImpl.BuilderImpl();
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder id(String id);
|
||||
|
||||
Builder lineWidth(int lineWidth);
|
||||
|
||||
Builder ownerRequirement(Requirement[] requirements);
|
||||
|
||||
Builder viewerRequirement(Requirement[] requirements);
|
||||
|
||||
Builder carouselText(CarouselText[] carouselTexts);
|
||||
|
||||
Builder opacity(byte opacity);
|
||||
|
||||
Builder backgroundColor(int backgroundColor);
|
||||
|
||||
Builder hasShadow(boolean hasShadow);
|
||||
|
||||
Builder seeThrough(boolean seeThrough);
|
||||
|
||||
Builder useDefaultBackgroundColor(boolean useDefaultBackgroundColor);
|
||||
|
||||
Builder alignment(Alignment alignment);
|
||||
|
||||
Builder viewRange(float viewRange);
|
||||
|
||||
Builder shadowRadius(float shadowRadius);
|
||||
|
||||
Builder shadowStrength(float shadowStrength);
|
||||
|
||||
Builder scale(Vector3 scale);
|
||||
|
||||
Builder translation(Vector3 translation);
|
||||
|
||||
Builder affectedByCrouching(boolean affectedByCrouching);
|
||||
|
||||
Builder affectedByScaling(boolean affectedByScale);
|
||||
|
||||
NameTagConfig build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@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 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;
|
||||
|
||||
@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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
String id();
|
||||
|
||||
int entityID();
|
||||
|
||||
UUID uuid();
|
||||
|
||||
boolean affectedByCrouching();
|
||||
|
||||
boolean affectedByScaling();
|
||||
|
||||
void hide();
|
||||
|
||||
void hide(CNPlayer viewer);
|
||||
|
||||
void show();
|
||||
|
||||
void show(CNPlayer viewer);
|
||||
|
||||
void respawn();
|
||||
|
||||
void respawn(CNPlayer viewer);
|
||||
|
||||
byte opacity();
|
||||
|
||||
void updateOpacity(byte opacity);
|
||||
|
||||
void updateOpacity(CNPlayer viewer, byte opacity);
|
||||
|
||||
boolean canShow();
|
||||
|
||||
boolean canShow(CNPlayer viewer);
|
||||
|
||||
boolean isShown();
|
||||
|
||||
boolean isShown(CNPlayer viewer);
|
||||
|
||||
void tick();
|
||||
|
||||
void init();
|
||||
|
||||
double getTextHeight(CNPlayer viewer);
|
||||
|
||||
void updateScale(double scale);
|
||||
|
||||
void updateScale(CNPlayer viewer, double scale);
|
||||
|
||||
void updateTranslation();
|
||||
|
||||
Vector3 scale(CNPlayer viewer);
|
||||
|
||||
Vector3 translation(CNPlayer viewer);
|
||||
}
|
||||
@@ -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,29 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.api.manager;
|
||||
package net.momirealms.customnameplates.api.feature.tag;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface ActionBarManager {
|
||||
public interface TagRenderer {
|
||||
|
||||
/**
|
||||
* Get the actionbar sent by other plugins in MiniMessage format
|
||||
* Return "" if no other actionbar received
|
||||
*
|
||||
* @param player receiver
|
||||
* @return text
|
||||
*/
|
||||
@NotNull
|
||||
String getOtherPluginActionBar(Player player);
|
||||
double hatOffset();
|
||||
|
||||
void hatOffset(double hatOffset);
|
||||
|
||||
void onTick();
|
||||
|
||||
void destroy();
|
||||
|
||||
void addTag(Tag tag);
|
||||
|
||||
Tag[] tags();
|
||||
|
||||
int removeTagIf(Predicate<Tag> predicate);
|
||||
|
||||
int tagIndex(Tag tag);
|
||||
|
||||
void addTag(Tag tag, int index);
|
||||
|
||||
void removeTag(Tag tag);
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.feature.Feature;
|
||||
import net.momirealms.customnameplates.api.network.Tracker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class TagRendererImpl implements TagRenderer {
|
||||
|
||||
private final CNPlayer owner;
|
||||
private final UnlimitedTagManager manager;
|
||||
private Tag[] tags;
|
||||
private double hatOffset;
|
||||
|
||||
public TagRendererImpl(UnlimitedTagManager manager, CNPlayer owner) {
|
||||
this.owner = owner;
|
||||
this.manager = manager;
|
||||
List<NameTag> senderList = new ArrayList<>();
|
||||
for (NameTagConfig config : manager.allConfigs()) {
|
||||
NameTag sender = new NameTag(owner, config, this);
|
||||
senderList.add(sender);
|
||||
this.owner.addFeature(sender);
|
||||
}
|
||||
this.tags = senderList.toArray(new Tag[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double hatOffset() {
|
||||
return hatOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hatOffset(double hatOffset) {
|
||||
if (hatOffset != this.hatOffset) {
|
||||
this.hatOffset = hatOffset;
|
||||
for (Tag tag : tags) {
|
||||
tag.updateTranslation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
HashSet<CNPlayer> playersToUpdatePassengers = new HashSet<>();
|
||||
for (Tag display : tags) {
|
||||
boolean canShow = display.canShow();
|
||||
// 能大众显示
|
||||
if (canShow) {
|
||||
// 当前大众显示
|
||||
if (display.isShown()) {
|
||||
for (CNPlayer nearby : owner.nearbyPlayers()) {
|
||||
// 如果已经展示了
|
||||
if (display.isShown(nearby)) {
|
||||
// 不满足条件就撤掉
|
||||
if (!display.canShow(nearby)) {
|
||||
display.hide(nearby);
|
||||
}
|
||||
} else {
|
||||
// 未展示,则检测条件,可以就上
|
||||
if (display.canShow(nearby)) {
|
||||
display.show(nearby);
|
||||
playersToUpdatePassengers.add(nearby);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新一下文字顺序,放在后面是为了防止已经被hide的玩家多收一个包
|
||||
display.tick();
|
||||
} else {
|
||||
// 之前隐藏,现在开始大众显示
|
||||
// 需要重置文字顺序
|
||||
display.init();
|
||||
// 更新一下文字顺序
|
||||
display.tick();
|
||||
display.show();
|
||||
for (CNPlayer nearby : owner.nearbyPlayers()) {
|
||||
if (display.canShow(nearby) && !display.isShown(nearby)) {
|
||||
display.show(nearby);
|
||||
playersToUpdatePassengers.add(nearby);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 不能展示的情况
|
||||
// 如果已经展示了,就咔掉所有玩家
|
||||
if (display.isShown()) {
|
||||
display.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update passengers
|
||||
Set<Integer> realPassengers = owner.passengers();
|
||||
for (CNPlayer nearby : playersToUpdatePassengers) {
|
||||
updatePassengers(nearby, realPassengers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
for (Tag tag : this.tags) {
|
||||
tag.hide();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.removeFeature(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePlayerRemove(CNPlayer another) {
|
||||
for (Tag display : this.tags) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
display.hide(another);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTag(Tag tag) {
|
||||
Tag[] newTags = new Tag[this.tags.length + 1];
|
||||
System.arraycopy(this.tags, 0, newTags, 0, this.tags.length);
|
||||
newTags[this.tags.length] = tag;
|
||||
this.tags = newTags;
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.addFeature(feature);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag[] tags() {
|
||||
return this.tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int removeTagIf(Predicate<Tag> predicate) {
|
||||
Set<Integer> removedIndexes = new HashSet<>();
|
||||
for (int i = 0; i < this.tags.length; i++) {
|
||||
if (predicate.test(this.tags[i])) {
|
||||
removedIndexes.add(i);
|
||||
this.tags[i].hide();
|
||||
if (this.tags[i] instanceof Feature feature) {
|
||||
this.owner.removeFeature(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removedIndexes.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
Tag[] newTags = new Tag[this.tags.length - removedIndexes.size()];
|
||||
int newIndex = 0;
|
||||
for (int i = 0; i < this.tags.length; i++) {
|
||||
if (!removedIndexes.contains(i)) {
|
||||
newTags[newIndex++] = this.tags[i];
|
||||
}
|
||||
}
|
||||
this.tags = newTags;
|
||||
return removedIndexes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int tagIndex(Tag tag) {
|
||||
for (int i = 0; i < this.tags.length; i++) {
|
||||
if (this.tags[i].equals(tag)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTag(Tag tag, int index) {
|
||||
if (index < 0 || index > this.tags.length) {
|
||||
throw new IndexOutOfBoundsException("Index out of bounds: " + index);
|
||||
}
|
||||
Tag[] newTags = new Tag[this.tags.length + 1];
|
||||
System.arraycopy(this.tags, 0, newTags, 0, index);
|
||||
newTags[index] = tag;
|
||||
System.arraycopy(this.tags, index, newTags, index + 1, this.tags.length - index);
|
||||
this.tags = newTags;
|
||||
tag.show();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.addFeature(feature);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTag(Tag tag) {
|
||||
int i = 0;
|
||||
boolean has = false;
|
||||
for (Tag display : this.tags) {
|
||||
if (display == tag) {
|
||||
has = true;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (has) {
|
||||
Tag[] newTags = new Tag[this.tags.length - 1];
|
||||
System.arraycopy(this.tags, 0, newTags, 0, i);
|
||||
System.arraycopy(this.tags, i + 1, newTags, i, (this.tags.length - i) - 1);
|
||||
this.tags = newTags;
|
||||
tag.hide();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.removeFeature(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePlayerAdd(CNPlayer another) {
|
||||
boolean updatePassengers = false;
|
||||
for (Tag display : this.tags) {
|
||||
if (display.isShown()) {
|
||||
if (!display.isShown(another)) {
|
||||
if (display.canShow(another)) {
|
||||
display.show(another);
|
||||
updatePassengers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updatePassengers) {
|
||||
Set<Integer> realPassengers = owner.passengers();
|
||||
updatePassengers(another, realPassengers);
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePassengers(CNPlayer another, Set<Integer> realPassengers) {
|
||||
Set<Integer> fakePassengers = owner.getTrackedPassengerIds(another);
|
||||
fakePassengers.addAll(realPassengers);
|
||||
int[] passengers = new int[fakePassengers.size()];
|
||||
int index = 0;
|
||||
for (int passenger : fakePassengers) {
|
||||
passengers[index++] = passenger;
|
||||
}
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().setPassengersPacket(owner.entityID(), passengers);
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet);
|
||||
}
|
||||
|
||||
public void handleEntityDataChange(CNPlayer another, boolean isCrouching) {
|
||||
Tracker properties = owner.getTracker(another);
|
||||
// should never be null
|
||||
if (properties == null) return;
|
||||
properties.setCrouching(isCrouching);
|
||||
for (Tag display : this.tags) {
|
||||
if (display.affectedByCrouching()) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
if (isCrouching) {
|
||||
display.updateOpacity(another, (byte) 64);
|
||||
} else {
|
||||
display.updateOpacity(another, display.opacity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleAttributeChange(CNPlayer another, double scale) {
|
||||
boolean updatePassengers = false;
|
||||
Tracker properties = owner.getTracker(another);
|
||||
// should never be null
|
||||
if (properties == null) return;
|
||||
properties.setScale(scale);
|
||||
for (Tag display : this.tags) {
|
||||
if (display.affectedByScaling()) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
display.updateScale(another, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.tag;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public interface UnlimitedTagManager extends Reloadable {
|
||||
|
||||
void onTick();
|
||||
|
||||
boolean isAlwaysShow();
|
||||
|
||||
NameTagConfig getConfig(String name);
|
||||
|
||||
NameTagConfig[] allConfigs();
|
||||
|
||||
void setPreviewing(CNPlayer player, boolean preview);
|
||||
|
||||
int previewDuration();
|
||||
|
||||
TagRenderer getTagRender(CNPlayer owner);
|
||||
|
||||
@ApiStatus.Internal
|
||||
void onAddPlayer(CNPlayer owner, CNPlayer added);
|
||||
|
||||
@ApiStatus.Internal
|
||||
void onRemovePlayer(CNPlayer owner, CNPlayer removed);
|
||||
|
||||
@ApiStatus.Internal
|
||||
void onPlayerDataSet(CNPlayer owner, CNPlayer viewer, boolean isCrouching);
|
||||
|
||||
@ApiStatus.Internal
|
||||
void onPlayerAttributeSet(CNPlayer owner, CNPlayer viewer, double scale);
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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 dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customnameplates.api.AbstractCNPlayer;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
import net.momirealms.customnameplates.api.feature.JoinQuitListener;
|
||||
import net.momirealms.customnameplates.api.helper.VersionHelper;
|
||||
import net.momirealms.customnameplates.api.network.Tracker;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import net.momirealms.customnameplates.api.util.Alignment;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import net.momirealms.customnameplates.api.util.Vector3;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitListener {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final LinkedHashMap<String, NameTagConfig> configs = new LinkedHashMap<>();
|
||||
private final ConcurrentHashMap<UUID, TagRendererImpl> tagRenderers = new ConcurrentHashMap<>();
|
||||
private NameTagConfig[] configArray = new NameTagConfig[0];
|
||||
private int previewDuration;
|
||||
private boolean alwaysShow;
|
||||
|
||||
public UnlimitedTagManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreviewing(CNPlayer player, boolean preview) {
|
||||
boolean isPreviewing = player.isPreviewing();
|
||||
if (isPreviewing) {
|
||||
if (preview) return;
|
||||
plugin.getUnlimitedTagManager().onRemovePlayer(player, player);
|
||||
player.removePlayerFromTracker(player);
|
||||
((AbstractCNPlayer) player).setPreviewing(false);
|
||||
} else {
|
||||
if (!preview) return;
|
||||
Tracker tracker = player.addPlayerToTracker(player);
|
||||
tracker.setScale(player.scale());
|
||||
tracker.setCrouching(player.isCrouching());
|
||||
plugin.getUnlimitedTagManager().onAddPlayer(player, player);
|
||||
((AbstractCNPlayer) player).setPreviewing(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previewDuration() {
|
||||
return previewDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerJoin(CNPlayer player) {
|
||||
TagRendererImpl sender = new TagRendererImpl(this, player);
|
||||
sender.onTick();
|
||||
TagRendererImpl previous = tagRenderers.put(player.uuid(), sender);
|
||||
if (previous != null) {
|
||||
previous.destroy();
|
||||
}
|
||||
setPreviewing(player, isAlwaysShow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerQuit(CNPlayer player) {
|
||||
TagRendererImpl sender = tagRenderers.remove(player.uuid());
|
||||
if (sender != null) {
|
||||
sender.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (!ConfigManager.nameplateModule()) return;
|
||||
this.loadConfig();
|
||||
this.resetArray();
|
||||
for (CNPlayer online : plugin.getOnlinePlayers()) {
|
||||
onPlayerJoin(online);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
for (TagRendererImpl sender : tagRenderers.values()) {
|
||||
sender.destroy();
|
||||
}
|
||||
this.tagRenderers.clear();
|
||||
this.configs.clear();
|
||||
this.resetArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
for (TagRendererImpl sender : tagRenderers.values()) {
|
||||
sender.onTick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysShow() {
|
||||
return alwaysShow;
|
||||
}
|
||||
|
||||
private void resetArray() {
|
||||
configArray = configs.values().toArray(new NameTagConfig[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NameTagConfig getConfig(String name) {
|
||||
return configs.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NameTagConfig[] allConfigs() {
|
||||
return configArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddPlayer(CNPlayer owner, CNPlayer added) {
|
||||
TagRendererImpl controller = tagRenderers.get(owner.uuid());
|
||||
if (controller != null) {
|
||||
controller.handlePlayerAdd(added);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagRenderer getTagRender(CNPlayer owner) {
|
||||
return tagRenderers.get(owner.uuid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemovePlayer(CNPlayer owner, CNPlayer removed) {
|
||||
TagRendererImpl controller = tagRenderers.get(owner.uuid());
|
||||
if (controller != null) {
|
||||
controller.handlePlayerRemove(removed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerDataSet(CNPlayer owner, CNPlayer viewer, boolean isCrouching) {
|
||||
TagRendererImpl controller = tagRenderers.get(owner.uuid());
|
||||
if (controller != null) {
|
||||
controller.handleEntityDataChange(viewer, isCrouching);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerAttributeSet(CNPlayer owner, CNPlayer viewer, double scale) {
|
||||
TagRendererImpl controller = tagRenderers.get(owner.uuid());
|
||||
if (controller != null) {
|
||||
controller.handleAttributeChange(viewer, scale);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
plugin.getConfigManager().saveResource("configs" + File.separator + "nameplate.yml");
|
||||
YamlDocument document = plugin.getConfigManager().loadData(new File(plugin.getDataDirectory().toFile(), "configs" + File.separator + "nameplate.yml"));
|
||||
previewDuration = document.getInt("preview-duration", 5);
|
||||
alwaysShow = document.getBoolean("always-show", false);
|
||||
Section unlimitedSection = document.getSection("unlimited");
|
||||
if (unlimitedSection == null) return;
|
||||
for (Map.Entry<String, Object> entry : unlimitedSection.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (!(entry.getValue() instanceof Section section))
|
||||
return;
|
||||
Vector3 translation = ConfigUtils.vector3(section.getString("translation", "0,0,0"));
|
||||
this.configs.put(entry.getKey(),
|
||||
NameTagConfig.builder()
|
||||
.id(entry.getKey())
|
||||
.ownerRequirement(plugin.getRequirementManager().parseRequirements(section.getSection("owner-conditions")))
|
||||
.viewerRequirement(plugin.getRequirementManager().parseRequirements(section.getSection("viewer-conditions")))
|
||||
.translation(VersionHelper.isVersionNewerThan1_20_2() ? translation : translation.add(0,0.5,0))
|
||||
.scale(ConfigUtils.vector3(section.getString("scale", "1,1,1")))
|
||||
.alignment(Alignment.valueOf(section.getString("alignment", "CENTER")))
|
||||
.viewRange(section.getFloat("view-range", 1f))
|
||||
.shadowRadius(section.getFloat("shadow-radius", 0f))
|
||||
.shadowStrength(section.getFloat("shadow-strength", 1f))
|
||||
.lineWidth(section.getInt("line-width", 200))
|
||||
.hasShadow(section.getBoolean("has-shadow", false))
|
||||
.seeThrough(section.getBoolean("is-see-through", false))
|
||||
.opacity(section.getByte("opacity", (byte) -1))
|
||||
.useDefaultBackgroundColor(section.getBoolean("use-default-background-color", false))
|
||||
.backgroundColor(ConfigUtils.argb(section.getString("background-color", "64,0,0,0")))
|
||||
.affectedByCrouching(section.getBoolean("affected-by-crouching", true))
|
||||
.affectedByScaling(section.getBoolean("affected-by-scale-attribute", true))
|
||||
.carouselText(
|
||||
section.contains("text") ?
|
||||
new CarouselText[]{new CarouselText(-1, new Requirement[0], section.getString("text"), false)} :
|
||||
ConfigUtils.carouselTexts(section.getSection("text-display-order"))
|
||||
)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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(4, r -> {
|
||||
Thread thread = Executors.defaultThreadFactory().newThread(r);
|
||||
thread.setName("customnameplates-scheduler");
|
||||
return thread;
|
||||
});
|
||||
executor.setRemoveOnCancelPolicy(true);
|
||||
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
|
||||
this.miniMessageToComponentCache =
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.executor(executor)
|
||||
.maximumSize(512)
|
||||
.build();
|
||||
this.miniMessageToMinecraftComponentCache =
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.executor(executor)
|
||||
.maximumSize(512)
|
||||
.build();
|
||||
this.minecraftComponentToMiniMessageCache =
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.executor(executor)
|
||||
.maximumSize(512)
|
||||
.build();
|
||||
this.jsonToMiniMessageCache =
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.executor(executor)
|
||||
.maximumSize(512)
|
||||
.build();
|
||||
}
|
||||
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static String surroundWithNameplatesFont(String text) {
|
||||
return surroundWithMiniMessageFont(text, ConfigManager.namespace() + ":" + ConfigManager.font());
|
||||
}
|
||||
|
||||
public static String removeShadowTricky(String text) {
|
||||
return "<#FFFEFD>" + text + "</#FFFEFD>";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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("<r><!i>");
|
||||
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,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.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_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,153 +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 net.momirealms.customnameplates.api.mechanic.bubble.provider.AbstractChatProvider;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface BubbleManager {
|
||||
|
||||
/**
|
||||
* Set a custom chat provider
|
||||
*
|
||||
* @param provider provider
|
||||
* @return success or not
|
||||
*/
|
||||
boolean setCustomChatProvider(AbstractChatProvider provider);
|
||||
|
||||
/**
|
||||
* Remove a custom chat provider
|
||||
*
|
||||
* @return success or not
|
||||
*/
|
||||
boolean removeCustomChatProvider();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
void onChat(Player player, String text, String channel);
|
||||
|
||||
/**
|
||||
* 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,316 +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();
|
||||
|
||||
void handlePlayerJoin(Player player);
|
||||
|
||||
void handlePlayerQuit(Player player);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param isJoin
|
||||
*/
|
||||
@Nullable
|
||||
NameplatePlayer createNameTag(@NotNull Player player, boolean isJoin);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Nullable
|
||||
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,47 +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.team.TeamTagPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface TeamTagManager {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return team tag
|
||||
*/
|
||||
@NotNull
|
||||
TeamTagPlayer createTagForPlayer(Player player, String prefix, String suffix);
|
||||
|
||||
/**
|
||||
* Remove a team tag from map by uuid
|
||||
*
|
||||
* @param uuid uuid
|
||||
* @return team tag
|
||||
*/
|
||||
@Nullable
|
||||
TeamTagPlayer removeTeamPlayerFromMap(UUID uuid);
|
||||
}
|
||||
@@ -1,64 +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
|
||||
* @param isJoin
|
||||
* @return entity tag instance
|
||||
*/
|
||||
EntityTagPlayer createOrGetTagForPlayer(Player player, boolean isJoin);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user