Compare commits
84
Commits
3.0-beta-1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26b593950d | ||
|
|
63896acda6 | ||
|
|
6eb5dee611 | ||
|
|
69869d1cb1 | ||
|
|
2e702d8945 | ||
|
|
56c77bd294 | ||
|
|
4d195820a0 | ||
|
|
2874ab7c4e | ||
|
|
cd1a0bffb6 | ||
|
|
20d3919c6b | ||
|
|
fccaa059ff | ||
|
|
ed2fb60748 | ||
|
|
378dc2e3bc | ||
|
|
6144423110 | ||
|
|
d21fa8a3f7 | ||
|
|
7e68a6cda7 | ||
|
|
3df6d66efb | ||
|
|
001ecd28ed | ||
|
|
6fe8625722 | ||
|
|
43e006f49d | ||
|
|
8d63ad9c74 | ||
|
|
5c2411e420 | ||
|
|
a57cfb0842 | ||
|
|
e4d7fb4346 | ||
|
|
9a9865c424 | ||
|
|
f6b8ce253f | ||
|
|
144b358768 | ||
|
|
0fd7ac1a79 | ||
|
|
67f0e60327 | ||
|
|
d10eb6de67 | ||
|
|
8cfd098be9 | ||
|
|
e3d81e7c0c | ||
|
|
018dc18eee | ||
|
|
366cda6bef | ||
|
|
ca70dfb2b4 | ||
|
|
d59ac96f48 | ||
|
|
f5d2d6a0bc | ||
|
|
7d6fba25e6 | ||
|
|
fcb045e0c8 | ||
|
|
df098a053e | ||
|
|
2958b4e1db | ||
|
|
84a37ed619 | ||
|
|
f66c800f3a | ||
|
|
0fb4ae37e4 | ||
|
|
9a9add1f03 | ||
|
|
5d48530eb6 | ||
|
|
f5e33f5647 | ||
|
|
ffdc7c49ce | ||
|
|
46d922ab15 | ||
|
|
aee8ebf9ae | ||
|
|
be086cd91f | ||
|
|
0b96cefcf2 | ||
|
|
8867b25307 | ||
|
|
bd6caee58f | ||
|
|
d0b057b391 | ||
|
|
2e03248555 | ||
|
|
5898d8e3d4 | ||
|
|
8bcb7d3380 | ||
|
|
59dda019d8 | ||
|
|
7512a97461 | ||
|
|
63075ad1bb | ||
|
|
2c9bdc662a | ||
|
|
545826801a | ||
|
|
26c30b8bab | ||
|
|
c022319b67 | ||
|
|
37da5df7e6 | ||
|
|
aa919d18e0 | ||
|
|
7eb3296294 | ||
|
|
d84c9f7031 | ||
|
|
ec840036ac | ||
|
|
a168cb8591 | ||
|
|
8856831a94 | ||
|
|
a387cf5127 | ||
|
|
6b2bbea6e1 | ||
|
|
67732ecf76 | ||
|
|
f361ad1015 | ||
|
|
57a1593315 | ||
|
|
a424c3345a | ||
|
|
047852eed9 | ||
|
|
5d2d3e0933 | ||
|
|
efe90b95b5 | ||
|
|
cad0e07411 | ||
|
|
f6de779090 | ||
|
|
5df341b2a1 |
No files matched your search
@@ -5,6 +5,9 @@ target/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### Unfinished ###
|
||||
platforms/sponge/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||

|
||||

|
||||
|
||||
## How to build
|
||||
## How to Build
|
||||
|
||||
#### Command Line
|
||||
Install JDK 17 & 21. \
|
||||
@@ -22,10 +22,17 @@ Execute ".\gradlew build" and get the artifact under /target folder
|
||||
Import the project and execute gradle build action. \
|
||||
Get the artifact under /target folder
|
||||
|
||||
## Support the developer
|
||||
## How to Contribute
|
||||
|
||||
Polymart: https://polymart.org/resource/customnameplates.2543 \
|
||||
Afdian: https://afdian.com/@xiaomomi
|
||||
#### Translations
|
||||
Clone this project and create a new language file in the /common/src/main/resources/translations directory. \
|
||||
Once your changes are ready, open a pull request for review. We appreciate your works!
|
||||
|
||||
## Support the Developer
|
||||
|
||||
Polymart: https://polymart.org/resource/customnameplates.2543/ \
|
||||
BuiltByBit: https://builtbybit.com/resources/customnameplates.36359/ \
|
||||
Afdian: https://afdian.com/@xiaomomi/
|
||||
|
||||
## CustomNameplates API
|
||||
|
||||
|
||||
+14
-8
@@ -4,6 +4,9 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://jitpack.io/")
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -20,14 +23,8 @@ dependencies {
|
||||
compileOnly("io.netty:netty-all:4.1.113.Final")
|
||||
// GSON
|
||||
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
archiveClassifier = ""
|
||||
relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
|
||||
relocate("dev.dejvokep", "net.momirealms.customnameplates.libraries")
|
||||
}
|
||||
// Fast util
|
||||
compileOnly("it.unimi.dsi:fastutil:${rootProject.properties["fastutil_version"]}")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -44,6 +41,15 @@ tasks.withType<JavaCompile> {
|
||||
dependsOn(tasks.clean)
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
archiveClassifier = ""
|
||||
archiveFileName = "CustomNameplates-${rootProject.properties["project_version"]}.jar"
|
||||
relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
|
||||
relocate("dev.dejvokep", "net.momirealms.customnameplates.libraries")
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
|
||||
@@ -17,8 +17,12 @@
|
||||
|
||||
package net.momirealms.customnameplates.api;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.feature.Feature;
|
||||
import net.momirealms.customnameplates.api.feature.TickStampData;
|
||||
import net.momirealms.customnameplates.api.feature.TimeStampData;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TeamView;
|
||||
import net.momirealms.customnameplates.api.network.Tracker;
|
||||
import net.momirealms.customnameplates.api.placeholder.Placeholder;
|
||||
import net.momirealms.customnameplates.api.placeholder.PlayerPlaceholder;
|
||||
@@ -27,120 +31,135 @@ import net.momirealms.customnameplates.api.placeholder.SharedPlaceholder;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import net.momirealms.customnameplates.api.storage.data.PlayerData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
|
||||
protected final CustomNameplates plugin;
|
||||
protected final Object player;
|
||||
protected final Channel channel;
|
||||
|
||||
private boolean isLoaded = false;
|
||||
protected Object player;
|
||||
|
||||
private boolean isPreviewing = false;
|
||||
private volatile boolean isLoaded = false;
|
||||
private volatile boolean tempPreviewing = false;
|
||||
private volatile boolean toggleablePreviewing = false;
|
||||
|
||||
private String equippedNameplate;
|
||||
private String equippedBubble;
|
||||
|
||||
private final Map<Integer, TickStampData<String>> cachedValues = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TickStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>();
|
||||
private final TeamView teamView = new TeamView();
|
||||
|
||||
private final Map<Requirement, TickStampData<Boolean>> cachedRequirements = new ConcurrentHashMap<>();
|
||||
private final Map<Requirement, WeakHashMap<CNPlayer, TickStampData<Boolean>>> cachedRelationalRequirements = new ConcurrentHashMap<>();
|
||||
// these maps might be visited by other threads through PlaceholderAPI
|
||||
private final Map<Integer, TimeStampData<String>> cachedValues = new ConcurrentHashMap<>(128);
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>(128);
|
||||
private final Map<Integer, TimeStampData<Boolean>> cachedRequirements = new ConcurrentHashMap<>(32);
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<Boolean>>> cachedRelationalRequirements = new ConcurrentHashMap<>(32);
|
||||
|
||||
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<>());
|
||||
private final Map<CNPlayer, Tracker> trackers = new WeakHashMap<>();
|
||||
private final ReadWriteLock trackerLock = new ReentrantReadWriteLock();
|
||||
|
||||
protected AbstractCNPlayer(CustomNameplates plugin, Object player) {
|
||||
protected AbstractCNPlayer(CustomNameplates plugin, Channel channel) {
|
||||
this.plugin = plugin;
|
||||
this.player = player;
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有处于激活状态的变量统筹起来并返回一个更新任务
|
||||
*
|
||||
* @return 更新任务
|
||||
*/
|
||||
@Override
|
||||
public List<Placeholder> activePlaceholdersToRefresh() {
|
||||
Placeholder[] activePlaceholders = activePlaceholders();
|
||||
List<Placeholder> placeholderWithChildren = new ArrayList<>();
|
||||
List<Placeholder> placeholderWithChildren = new ObjectArrayList<>();
|
||||
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 placeholderWithChildren.stream().distinct().toList();
|
||||
}
|
||||
|
||||
private String updatePlayerPlaceholder(PlayerPlaceholder placeholder) {
|
||||
TimeStampData<String> value = getRawPlayerValue(placeholder);
|
||||
if (value == null) {
|
||||
value = new TimeStampData<>(placeholder.request(this), MainTask.getTicks(), true);
|
||||
setPlayerValue(placeholder, value);
|
||||
return value.data();
|
||||
}
|
||||
return placeholdersToUpdate;
|
||||
if (value.ticks() != MainTask.getTicks()) {
|
||||
String newValue = placeholder.request(this);
|
||||
value.updateTicks(!value.data().equals(newValue));
|
||||
value.data(newValue);
|
||||
}
|
||||
return value.data();
|
||||
}
|
||||
|
||||
private void updateRelationalPlaceholder(RelationalPlaceholder placeholder, Collection<CNPlayer> others) {
|
||||
for (CNPlayer another : others) {
|
||||
updateRelationalPlaceholder(placeholder, another);
|
||||
}
|
||||
}
|
||||
|
||||
private String updateRelationalPlaceholder(RelationalPlaceholder placeholder, CNPlayer another) {
|
||||
TimeStampData<String> value = getRawRelationalValue(placeholder, another);
|
||||
if (value == null) {
|
||||
value = new TimeStampData<>(placeholder.request(this, another), MainTask.getTicks(), true);
|
||||
setRelationalValue(placeholder, another, value);
|
||||
return value.data();
|
||||
}
|
||||
if (value.ticks() != MainTask.getTicks()) {
|
||||
String newValue = placeholder.request(this, another);
|
||||
value.updateTicks(!value.data().equals(newValue));
|
||||
value.data(newValue);
|
||||
}
|
||||
return value.data();
|
||||
}
|
||||
|
||||
private String updateSharedPlaceholder(SharedPlaceholder placeholder) {
|
||||
TimeStampData<String> value = getRawSharedValue(placeholder);
|
||||
if (value == null) {
|
||||
String latest;
|
||||
if (MainTask.hasRequested(placeholder.countId())) {
|
||||
latest = placeholder.getLatestValue();
|
||||
} else {
|
||||
latest = placeholder.request();
|
||||
}
|
||||
value = new TimeStampData<>(latest, MainTask.getTicks(), true);
|
||||
setSharedValue(placeholder, value);
|
||||
return value.data();
|
||||
}
|
||||
if (value.ticks() != MainTask.getTicks()) {
|
||||
String latest;
|
||||
if (MainTask.hasRequested(placeholder.countId())) {
|
||||
latest = placeholder.getLatestValue();
|
||||
} else {
|
||||
latest = placeholder.request();
|
||||
}
|
||||
value.updateTicks(!value.data().equals(latest));
|
||||
value.data(latest);
|
||||
}
|
||||
return value.data();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceUpdate(Set<Placeholder> placeholders, Set<CNPlayer> others) {
|
||||
public void forceUpdatePlaceholders(Set<Placeholder> placeholders, Collection<CNPlayer> others) {
|
||||
if (placeholders.isEmpty()) return;
|
||||
List<Placeholder> placeholderWithChildren = new ArrayList<>();
|
||||
List<Placeholder> placeholderWithChildren = new ObjectArrayList<>();
|
||||
for (Placeholder placeholder : placeholders) {
|
||||
childrenFirstList(placeholder, placeholderWithChildren);
|
||||
}
|
||||
placeholderWithChildren = placeholderWithChildren.stream().distinct().toList();
|
||||
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);
|
||||
}
|
||||
}
|
||||
updatePlayerPlaceholder(playerPlaceholder);
|
||||
} else if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
updateRelationalPlaceholder(relationalPlaceholder, others);
|
||||
} 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);
|
||||
}
|
||||
updateSharedPlaceholder(sharedPlaceholder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,6 +175,17 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
private void parentLastList(Placeholder placeholder, List<Placeholder> list) {
|
||||
if (placeholder.parents().isEmpty()) {
|
||||
list.add(placeholder);
|
||||
} else {
|
||||
list.add(placeholder);
|
||||
for (Placeholder parent : placeholder.parents()) {
|
||||
parentLastList(parent, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
cachedValues.clear();
|
||||
cachedRelationalValues.clear();
|
||||
@@ -166,6 +196,15 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
feature2Placeholders.clear();
|
||||
}
|
||||
|
||||
public void setPlayer(Object player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel channel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Feature> activeFeatures(Placeholder placeholder) {
|
||||
return placeholder2Features.getOrDefault(placeholder, Collections.emptySet());
|
||||
@@ -180,13 +219,22 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
isLoaded = loaded;
|
||||
}
|
||||
|
||||
public void setPreviewing(boolean previewing) {
|
||||
isPreviewing = previewing;
|
||||
public void setTempPreviewing(boolean previewing) {
|
||||
this.tempPreviewing = previewing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreviewing() {
|
||||
return isPreviewing;
|
||||
public boolean isTempPreviewing() {
|
||||
return tempPreviewing;
|
||||
}
|
||||
|
||||
public void setToggleablePreviewing(boolean previewing) {
|
||||
this.toggleablePreviewing = previewing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToggleablePreviewing() {
|
||||
return toggleablePreviewing;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,13 +245,10 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
@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<>();
|
||||
});
|
||||
Set<Placeholder> allPlaceholders = feature.allPlaceholders();
|
||||
feature2Placeholders.put(feature, allPlaceholders);
|
||||
for (Placeholder placeholder : allPlaceholders) {
|
||||
Set<Feature> featureSet = placeholder2Features.computeIfAbsent(placeholder, k -> new ObjectOpenHashSet<>());
|
||||
featureSet.add(feature);
|
||||
}
|
||||
}
|
||||
@@ -222,85 +267,99 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Placeholder placeholder, TickStampData<String> value) {
|
||||
public void setPlayerValue(PlayerPlaceholder placeholder, TimeStampData<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;
|
||||
public void setSharedValue(SharedPlaceholder placeholder, TimeStampData<String> value) {
|
||||
cachedValues.put(placeholder.countId(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRelationalValue(Placeholder placeholder, CNPlayer another, TickStampData<String> value) {
|
||||
WeakHashMap<CNPlayer, TickStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
|
||||
public void setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, TimeStampData<String> value) {
|
||||
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
|
||||
map.put(another, value);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean setPlayerValue(PlayerPlaceholder placeholder, String value) {
|
||||
// TimeStampData<String> previous = cachedValues.get(placeholder.countId());
|
||||
// int currentTicks = MainTask.getTicks();
|
||||
// boolean changed = false;
|
||||
// if (previous != null) {
|
||||
// if (previous.ticks() == currentTicks) {
|
||||
// return false;
|
||||
// }
|
||||
// String data = previous.data();
|
||||
// if (!data.equals(value)) {
|
||||
// changed = true;
|
||||
// previous.data(value);
|
||||
// previous.updateTicks(true);
|
||||
// }
|
||||
// } else {
|
||||
// changed= true;
|
||||
// previous = new TimeStampData<>(value, currentTicks, true);
|
||||
// cachedValues.put(placeholder.countId(), previous);
|
||||
// }
|
||||
// return changed;
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public boolean setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, String value) {
|
||||
// WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
|
||||
// TimeStampData<String> previous = map.get(another);
|
||||
// int currentTicks = MainTask.getTicks();
|
||||
// boolean changed = false;
|
||||
// if (previous != null) {
|
||||
// if (previous.ticks() == currentTicks) {
|
||||
// return false;
|
||||
// }
|
||||
// String data = previous.data();
|
||||
// if (!data.equals(value)) {
|
||||
// changed = true;
|
||||
// previous.data(value);
|
||||
// previous.updateTicks(true);
|
||||
// }
|
||||
// } else {
|
||||
// changed= true;
|
||||
// previous = new TimeStampData<>(value, currentTicks, true);
|
||||
// map.put(another, previous);
|
||||
// }
|
||||
// return changed;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public 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;
|
||||
public @NotNull String getCachedSharedValue(SharedPlaceholder placeholder) {
|
||||
return updateSharedPlaceholder(placeholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getData(Placeholder placeholder) {
|
||||
return Optional.ofNullable(cachedValues.get(placeholder.countId())).map(TickStampData::data).orElse(placeholder.id());
|
||||
public @NotNull String getCachedPlayerValue(PlayerPlaceholder placeholder) {
|
||||
return updatePlayerPlaceholder(placeholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickStampData<String> getValue(Placeholder placeholder) {
|
||||
public @NotNull String getCachedRelationalValue(RelationalPlaceholder placeholder, CNPlayer another) {
|
||||
return updateRelationalPlaceholder(placeholder, another);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TimeStampData<String> getRawPlayerValue(PlayerPlaceholder placeholder) {
|
||||
return cachedValues.get(placeholder.countId());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public @NotNull String getRelationalData(Placeholder placeholder, CNPlayer another) {
|
||||
WeakHashMap<CNPlayer, TickStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
|
||||
if (map == null) {
|
||||
return placeholder.id();
|
||||
}
|
||||
return Optional.ofNullable(map.get(another)).map(TickStampData::data).orElse(placeholder.id());
|
||||
public TimeStampData<String> getRawSharedValue(SharedPlaceholder placeholder) {
|
||||
return cachedValues.get(placeholder.countId());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TickStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another) {
|
||||
WeakHashMap<CNPlayer, TickStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
|
||||
public TimeStampData<String> getRawRelationalValue(RelationalPlaceholder placeholder, CNPlayer another) {
|
||||
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -309,7 +368,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
|
||||
@Override
|
||||
public Placeholder[] activePlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
Set<Placeholder> placeholders = new ObjectOpenHashSet<>();
|
||||
for (Feature feature : activeFeatures) {
|
||||
placeholders.addAll(feature.activePlaceholders());
|
||||
}
|
||||
@@ -320,7 +379,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
public boolean isMet(Requirement[] requirements) {
|
||||
int currentTicks = MainTask.getTicks();
|
||||
for (Requirement requirement : requirements) {
|
||||
TickStampData<Boolean> data = cachedRequirements.get(requirement);
|
||||
TimeStampData<Boolean> data = cachedRequirements.get(requirement.countId());
|
||||
if (data != null) {
|
||||
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
|
||||
if (!data.data()) {
|
||||
@@ -336,8 +395,8 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
} else {
|
||||
boolean satisfied = requirement.isSatisfied(this, this);
|
||||
data = new TickStampData<>(satisfied, currentTicks, true);
|
||||
cachedRequirements.put(requirement, data);
|
||||
data = new TimeStampData<>(satisfied, currentTicks, true);
|
||||
cachedRequirements.put(requirement.countId(), data);
|
||||
if (!satisfied) {
|
||||
return false;
|
||||
}
|
||||
@@ -350,8 +409,8 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
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);
|
||||
WeakHashMap<CNPlayer, TimeStampData<Boolean>> innerMap = cachedRelationalRequirements.computeIfAbsent(requirement.countId(), k -> new WeakHashMap<>());
|
||||
TimeStampData<Boolean> data = innerMap.get(another);
|
||||
if (data != null) {
|
||||
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
|
||||
if (!data.data()) {
|
||||
@@ -367,7 +426,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
} else {
|
||||
boolean satisfied = requirement.isSatisfied(this, another);
|
||||
data = new TickStampData<>(satisfied, currentTicks, true);
|
||||
data = new TimeStampData<>(satisfied, currentTicks, true);
|
||||
innerMap.put(another, data);
|
||||
if (!satisfied) {
|
||||
return false;
|
||||
@@ -379,54 +438,90 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
|
||||
@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);
|
||||
trackerLock.writeLock().lock();
|
||||
try {
|
||||
Tracker tracker = trackers.get(another);
|
||||
if (tracker != null) {
|
||||
return tracker;
|
||||
}
|
||||
tracker = new Tracker(another);
|
||||
trackers.put(another, tracker);
|
||||
return tracker;
|
||||
} finally {
|
||||
trackerLock.writeLock().unlock();
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePlayerFromTracker(CNPlayer another) {
|
||||
trackers.remove(another);
|
||||
trackerLock.writeLock().lock();
|
||||
try {
|
||||
trackers.remove(another);
|
||||
} finally {
|
||||
trackerLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CNPlayer> nearbyPlayers() {
|
||||
return new HashSet<>(trackers.keySet());
|
||||
public Collection<CNPlayer> nearbyPlayers() {
|
||||
trackerLock.readLock().lock();
|
||||
try {
|
||||
// Create a snapshot of keys to avoid concurrent modification
|
||||
return new ObjectArrayList<>(trackers.keySet());
|
||||
} finally {
|
||||
trackerLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trackPassengers(CNPlayer another, int... passengers) {
|
||||
Tracker tracker = trackers.get(another);
|
||||
if (tracker != null) {
|
||||
for (int passenger : passengers) {
|
||||
tracker.addPassengerID(passenger);
|
||||
}
|
||||
}
|
||||
trackerLock.writeLock().lock();
|
||||
try {
|
||||
Tracker tracker = trackers.get(another);
|
||||
if (tracker != null) {
|
||||
for (int passenger : passengers) {
|
||||
tracker.addPassengerID(passenger);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
trackerLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void untrackPassengers(CNPlayer another, int... passengers) {
|
||||
Optional.ofNullable(trackers.get(another)).ifPresent(tracker -> {
|
||||
for (int passenger : passengers) {
|
||||
tracker.removePassengerID(passenger);
|
||||
trackerLock.writeLock().lock();
|
||||
try {
|
||||
Tracker tracker = trackers.get(another);
|
||||
if (tracker != null) {
|
||||
for (int passenger : passengers) {
|
||||
tracker.removePassengerID(passenger);
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
trackerLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getTrackedPassengerIds(CNPlayer another) {
|
||||
return Optional.ofNullable(trackers.get(another)).map(Tracker::getPassengerIDs).orElse(new HashSet<>());
|
||||
trackerLock.readLock().lock();
|
||||
try {
|
||||
Tracker tracker = trackers.get(another);
|
||||
return tracker != null ? tracker.getPassengerIDs() : new ObjectOpenHashSet<>();
|
||||
} finally {
|
||||
trackerLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracker getTracker(CNPlayer another) {
|
||||
return trackers.get(another);
|
||||
trackerLock.readLock().lock();
|
||||
try {
|
||||
return trackers.get(another);
|
||||
} finally {
|
||||
trackerLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -455,7 +550,6 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
if (!isLoaded()) return false;
|
||||
if (!equippedNameplate.equals(this.equippedNameplate)) {
|
||||
this.equippedNameplate = equippedNameplate;
|
||||
// TODO 更新变量
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -466,9 +560,15 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
.uuid(uuid())
|
||||
.nameplate(equippedNameplate())
|
||||
.bubble(equippedBubble())
|
||||
.previewTags(isToggleablePreviewing())
|
||||
.build(), plugin.getScheduler().async());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeamView teamView() {
|
||||
return teamView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) return true;
|
||||
|
||||
@@ -17,15 +17,21 @@
|
||||
|
||||
package net.momirealms.customnameplates.api;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import net.momirealms.customnameplates.api.feature.Feature;
|
||||
import net.momirealms.customnameplates.api.feature.TickStampData;
|
||||
import net.momirealms.customnameplates.api.feature.TimeStampData;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TeamView;
|
||||
import net.momirealms.customnameplates.api.network.Tracker;
|
||||
import net.momirealms.customnameplates.api.placeholder.Placeholder;
|
||||
import net.momirealms.customnameplates.api.placeholder.PlayerPlaceholder;
|
||||
import net.momirealms.customnameplates.api.placeholder.RelationalPlaceholder;
|
||||
import net.momirealms.customnameplates.api.placeholder.SharedPlaceholder;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import net.momirealms.customnameplates.api.util.Vector3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -53,6 +59,13 @@ public interface CNPlayer {
|
||||
*/
|
||||
Object player();
|
||||
|
||||
/**
|
||||
* Returns the channel of the player
|
||||
*
|
||||
* @return the channel
|
||||
*/
|
||||
Channel channel();
|
||||
|
||||
/**
|
||||
* Returns the entity ID of the player.
|
||||
*
|
||||
@@ -81,6 +94,14 @@ public interface CNPlayer {
|
||||
*/
|
||||
boolean isOnline();
|
||||
|
||||
/**
|
||||
*
|
||||
* Checks if the player is on spectator mode
|
||||
*
|
||||
* @return true if the player is on spectator mode, false otherwise
|
||||
*/
|
||||
boolean isSpectator();
|
||||
|
||||
/**
|
||||
* Returns the scale of the player.
|
||||
*
|
||||
@@ -107,7 +128,14 @@ public interface CNPlayer {
|
||||
*
|
||||
* @return true if the player is previewing, false otherwise
|
||||
*/
|
||||
boolean isPreviewing();
|
||||
boolean isTempPreviewing();
|
||||
|
||||
/**
|
||||
* Checks if the player has turned their nameplate on
|
||||
*
|
||||
* @return true if the player has turned their nameplate on, false otherwise
|
||||
*/
|
||||
boolean isToggleablePreviewing();
|
||||
|
||||
/**
|
||||
* Checks if the player has the specified permission.
|
||||
@@ -166,7 +194,7 @@ public interface CNPlayer {
|
||||
* @param placeholders the placeholders to update
|
||||
* @param another the players related to the placeholders
|
||||
*/
|
||||
void forceUpdate(Set<Placeholder> placeholders, Set<CNPlayer> another);
|
||||
void forceUpdatePlaceholders(Set<Placeholder> placeholders, Collection<CNPlayer> another);
|
||||
|
||||
/**
|
||||
* Retrieves the cached data for a given placeholder.
|
||||
@@ -175,16 +203,16 @@ public interface CNPlayer {
|
||||
* @return the cached data as a string
|
||||
*/
|
||||
@NotNull
|
||||
String getData(Placeholder placeholder);
|
||||
String getCachedSharedValue(SharedPlaceholder placeholder);
|
||||
|
||||
/**
|
||||
* Retrieves the cached {@link TickStampData} for a given placeholder.
|
||||
* Retrieves the cached data for a given placeholder.
|
||||
*
|
||||
* @param placeholder the placeholder to retrieve data for
|
||||
* @return the cached TickStampData, or null if none exists
|
||||
* @return the cached data as a string
|
||||
*/
|
||||
@Nullable
|
||||
TickStampData<String> getValue(Placeholder placeholder);
|
||||
@NotNull
|
||||
String getCachedPlayerValue(PlayerPlaceholder placeholder);
|
||||
|
||||
/**
|
||||
* Retrieves the cached relational data between this player and another for a given placeholder.
|
||||
@@ -194,53 +222,79 @@ public interface CNPlayer {
|
||||
* @return the relational data as a string
|
||||
*/
|
||||
@NotNull
|
||||
String getRelationalData(Placeholder placeholder, CNPlayer another);
|
||||
String getCachedRelationalValue(RelationalPlaceholder placeholder, CNPlayer another);
|
||||
|
||||
/**
|
||||
* Retrieves the cached relational {@link TickStampData} for a given placeholder.
|
||||
* Retrieves the cached {@link TimeStampData} for a given placeholder.
|
||||
*
|
||||
* @param placeholder the placeholder to retrieve data for
|
||||
* @return the cached TickStampData, or null if none exists
|
||||
*/
|
||||
@Nullable
|
||||
TimeStampData<String> getRawPlayerValue(PlayerPlaceholder placeholder);
|
||||
|
||||
/**
|
||||
* Retrieves the cached {@link TimeStampData} for a given placeholder.
|
||||
*
|
||||
* @param placeholder the placeholder to retrieve data for
|
||||
* @return the cached TickStampData, or null if none exists
|
||||
*/
|
||||
@Nullable
|
||||
TimeStampData<String> getRawSharedValue(SharedPlaceholder placeholder);
|
||||
|
||||
/**
|
||||
* Retrieves the cached relational {@link TimeStampData} for a given placeholder.
|
||||
*
|
||||
* @param placeholder the relational placeholder
|
||||
* @param another the other player
|
||||
* @return the cached relational TickStampData, or null if none exists
|
||||
*/
|
||||
@Nullable
|
||||
TickStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another);
|
||||
TimeStampData<String> getRawRelationalValue(RelationalPlaceholder placeholder, CNPlayer another);
|
||||
|
||||
/**
|
||||
* Caches the specified {@link TickStampData} for the given placeholder.
|
||||
* Caches the specified {@link TimeStampData} for the given placeholder.
|
||||
*
|
||||
* @param placeholder the placeholder to cache
|
||||
* @param value the value to cache
|
||||
*/
|
||||
void setValue(Placeholder placeholder, TickStampData<String> value);
|
||||
void setPlayerValue(PlayerPlaceholder placeholder, TimeStampData<String> value);
|
||||
|
||||
/**
|
||||
* Caches the specified value for the given placeholder.
|
||||
* Caches the specified {@link TimeStampData} for the given placeholder.
|
||||
*
|
||||
* @param placeholder the placeholder to cache
|
||||
* @param value the value to cache
|
||||
* @return true if the value was changed, false otherwise
|
||||
*/
|
||||
boolean setValue(Placeholder placeholder, String value);
|
||||
void setSharedValue(SharedPlaceholder placeholder, TimeStampData<String> value);
|
||||
|
||||
/**
|
||||
* Caches the specified relational {@link TickStampData} for a given placeholder and player.
|
||||
* Caches the specified relational {@link TimeStampData} for a given placeholder and player.
|
||||
*
|
||||
* @param placeholder the relational placeholder
|
||||
* @param another the other player
|
||||
* @param value the value to cache
|
||||
*/
|
||||
void setRelationalValue(Placeholder placeholder, CNPlayer another, TickStampData<String> value);
|
||||
void setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, TimeStampData<String> value);
|
||||
|
||||
/**
|
||||
* Caches the specified relational value for a given placeholder and player.
|
||||
*
|
||||
* @param placeholder the relational placeholder
|
||||
* @param another the other player
|
||||
* @param value the value to cache
|
||||
* @return true if the value was changed, false otherwise
|
||||
*/
|
||||
boolean setRelationalValue(Placeholder placeholder, CNPlayer another, String value);
|
||||
// /**
|
||||
// * Caches the specified value for the given placeholder.
|
||||
// *
|
||||
// * @param placeholder the placeholder to cache
|
||||
// * @param value the value to cache
|
||||
// * @return true if the value was changed, false otherwise
|
||||
// */
|
||||
// boolean setPlayerValue(PlayerPlaceholder placeholder, String value);
|
||||
|
||||
// /**
|
||||
// * Caches the specified relational value for a given placeholder and player.
|
||||
// *
|
||||
// * @param placeholder the relational placeholder
|
||||
// * @param another the other player
|
||||
// * @param value the value to cache
|
||||
// * @return true if the value was changed, false otherwise
|
||||
// */
|
||||
// boolean setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, String value);
|
||||
|
||||
/**
|
||||
* Adds a feature to the player
|
||||
@@ -293,7 +347,7 @@ public interface CNPlayer {
|
||||
*
|
||||
* @return the set of nearby players
|
||||
*/
|
||||
Set<CNPlayer> nearbyPlayers();
|
||||
Collection<CNPlayer> nearbyPlayers();
|
||||
|
||||
/**
|
||||
* Adds passenger entities to the tracker for another player.
|
||||
@@ -370,4 +424,18 @@ public interface CNPlayer {
|
||||
* Save the player's current nameplate/bubble to database
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* Get the player's team view
|
||||
*
|
||||
* @return team view
|
||||
*/
|
||||
TeamView teamView();
|
||||
|
||||
/**
|
||||
* Check if the player is initialized
|
||||
*
|
||||
* @return initialized or not
|
||||
*/
|
||||
boolean isInitialized();
|
||||
}
|
||||
@@ -60,15 +60,20 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
protected boolean debug;
|
||||
protected boolean checkUpdate;
|
||||
protected boolean metrics;
|
||||
protected boolean nametagModule;
|
||||
protected boolean actionbarModule;
|
||||
protected boolean imageModule;
|
||||
protected boolean bossBarModule;
|
||||
protected boolean bubbleModule;
|
||||
protected boolean nameplateModule;
|
||||
protected boolean backgroundModule;
|
||||
protected int defaultRefreshInterval;
|
||||
protected boolean hideTeamNames;
|
||||
protected int defaultPlaceholderRefreshInterval;
|
||||
protected int defaultConditionRefreshInterval;
|
||||
protected int delaySend;
|
||||
protected boolean catchOtherActionBar;
|
||||
protected boolean displaySystemChat;
|
||||
protected int otherActionBarStayTime;
|
||||
|
||||
protected String namespace;
|
||||
protected String font;
|
||||
@@ -97,6 +102,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
protected boolean packItemsAdder;
|
||||
protected boolean packItemsAdderLegacy;
|
||||
protected boolean packOraxen;
|
||||
protected boolean packNexo;
|
||||
protected boolean packCreativeCentral;
|
||||
|
||||
protected boolean chatUnsafe;
|
||||
protected boolean chatTR;
|
||||
@@ -105,6 +112,10 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
protected boolean chatCarbon;
|
||||
protected boolean chatAdvanced;
|
||||
protected boolean chatEss;
|
||||
protected boolean chatChatControlRed;
|
||||
protected boolean chatChatty;
|
||||
|
||||
protected String configVersion;
|
||||
|
||||
public ConfigManager(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -113,42 +124,39 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
|
||||
@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()
|
||||
);
|
||||
configVersion = CustomNameplatesProperties.getValue("config");
|
||||
MAIN_CONFIG = loadConfig("config.yml",
|
||||
GeneralSettings.builder()
|
||||
.setRouteSeparator('.')
|
||||
.setUseDefaults(false)
|
||||
.build(),
|
||||
LoaderSettings
|
||||
.builder()
|
||||
.setAutoUpdate(true)
|
||||
.build(),
|
||||
DumperSettings.builder()
|
||||
.setEscapeUnprintable(false)
|
||||
.setScalarFormatter((tag, value, role, def) -> {
|
||||
if (role == NodeRole.KEY) {
|
||||
return ScalarStyle.PLAIN;
|
||||
} else {
|
||||
return tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : ScalarStyle.PLAIN;
|
||||
}
|
||||
})
|
||||
.build(),
|
||||
UpdaterSettings
|
||||
.builder()
|
||||
.setVersioning(new BasicVersioning("config-version"))
|
||||
.addIgnoredRoute(configVersion, "other-settings.placeholder-refresh-interval", '.')
|
||||
.addIgnoredRoute(configVersion, "other-settings.font-templates", '.')
|
||||
.addIgnoredRoute(configVersion, "other-settings.shift-fonts", '.')
|
||||
.build());
|
||||
try {
|
||||
MAIN_CONFIG.save(resolveConfig("config.yml").toFile());
|
||||
loadSettings();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
@@ -162,6 +170,7 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
checkUpdate = config.getBoolean("update-checker", false);
|
||||
|
||||
// Modules
|
||||
nametagModule = config.getBoolean("modules.nametags", true);
|
||||
actionbarModule = config.getBoolean("modules.actionbars", true);
|
||||
imageModule = config.getBoolean("modules.images", true);
|
||||
bossBarModule = config.getBoolean("modules.bossbars", true);
|
||||
@@ -174,6 +183,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
packItemsAdderLegacy = config.getBoolean("integrations.resource-pack.ItemsAdder-old-method", false);
|
||||
if (packItemsAdder) packItemsAdderLegacy = false;
|
||||
packOraxen = config.getBoolean("integrations.resource-pack.Oraxen", false);
|
||||
packCreativeCentral = config.getBoolean("integrations.resource-pack.Creative-Central");
|
||||
packNexo = config.getBoolean("integrations.resource-pack.Nexo");
|
||||
|
||||
chatUnsafe = config.getBoolean("other-settings.unsafe-chat-event", false);
|
||||
chatEss = config.getBoolean("integrations.chat.Essentials", false);
|
||||
@@ -182,6 +193,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
chatAdvanced = config.getBoolean("integrations.chat.AdvancedChat", false);
|
||||
chatTR = config.getBoolean("integrations.chat.TrChat", false);
|
||||
chatVenture = config.getBoolean("integrations.chat.VentureChat", false);
|
||||
chatChatControlRed = config.getBoolean("integrations.chat.ChatControlRed", false);
|
||||
chatChatty = config.getBoolean("integrations.chat.Chatty", false);
|
||||
|
||||
// Packs
|
||||
generateOnStart = !config.getBoolean("resource-pack.disable-generation-on-start", false);
|
||||
@@ -209,8 +222,12 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
|
||||
// Other settings
|
||||
delaySend = config.getInt("other-settings.send-delay", 0);
|
||||
defaultRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 10);
|
||||
defaultPlaceholderRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 1);
|
||||
defaultConditionRefreshInterval = config.getInt("other-settings.default-condition-refresh-interval", 20);
|
||||
catchOtherActionBar = config.getBoolean("other-settings.catch-other-plugin-actionbar", true);
|
||||
otherActionBarStayTime = config.getInt("other-settings.other-actionbar-stay-time", 3000);
|
||||
displaySystemChat = config.getBoolean("other-settings.display-system-actionbar", true);
|
||||
hideTeamNames = config.getBoolean("other-settings.hide-team-names", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,18 +271,34 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
return instance.font;
|
||||
}
|
||||
|
||||
public static String configVersion() {
|
||||
return instance.configVersion;
|
||||
}
|
||||
|
||||
public static char initialChar() {
|
||||
return instance.initialChar;
|
||||
}
|
||||
|
||||
public static boolean hideTeamNames() {
|
||||
return instance.hideTeamNames;
|
||||
}
|
||||
|
||||
public static boolean actionbarModule() {
|
||||
return instance.actionbarModule;
|
||||
}
|
||||
|
||||
public static boolean nametagModule() {
|
||||
return instance.nametagModule;
|
||||
}
|
||||
|
||||
public static boolean catchOtherActionBar() {
|
||||
return instance.catchOtherActionBar;
|
||||
}
|
||||
|
||||
public static boolean displaySystemChat() {
|
||||
return instance.displaySystemChat;
|
||||
}
|
||||
|
||||
public static boolean packItemsAdder() {
|
||||
return instance.packItemsAdder;
|
||||
}
|
||||
@@ -278,6 +311,12 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
return instance.packOraxen;
|
||||
}
|
||||
|
||||
public static boolean packNexo() {
|
||||
return instance.packNexo;
|
||||
}
|
||||
|
||||
public static boolean packCreativeCentral() { return instance.packCreativeCentral; }
|
||||
|
||||
public static boolean hideScoreBoardNumber() {
|
||||
return instance.hideScoreBoardNumber;
|
||||
}
|
||||
@@ -326,8 +365,16 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
return instance.metrics;
|
||||
}
|
||||
|
||||
public static int defaultRefreshInterval() {
|
||||
return instance.defaultRefreshInterval;
|
||||
public static int defaultPlaceholderRefreshInterval() {
|
||||
return instance.defaultPlaceholderRefreshInterval;
|
||||
}
|
||||
|
||||
public static int defaultConditionRefreshInterval() {
|
||||
return instance.defaultConditionRefreshInterval;
|
||||
}
|
||||
|
||||
public static int otherActionBarStayTime() {
|
||||
return instance.otherActionBarStayTime;
|
||||
}
|
||||
|
||||
public static boolean enableShader() {
|
||||
@@ -374,6 +421,14 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
return instance.chatAdvanced;
|
||||
}
|
||||
|
||||
public static boolean chatChatControlRed() {
|
||||
return instance.chatChatControlRed;
|
||||
}
|
||||
|
||||
public static boolean chatChatty() {
|
||||
return instance.chatChatty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlDocument loadConfig(String filePath) {
|
||||
return loadConfig(filePath, '.');
|
||||
@@ -410,6 +465,23 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlDocument loadConfig(String filePath, GeneralSettings generalSettings, LoaderSettings loaderSettings, DumperSettings dumperSettings, UpdaterSettings updaterSettings) {
|
||||
try (InputStream inputStream = new FileInputStream(resolveConfig(filePath).toFile())) {
|
||||
return YamlDocument.create(
|
||||
inputStream,
|
||||
plugin.getResourceStream(filePath),
|
||||
generalSettings,
|
||||
loaderSettings,
|
||||
dumperSettings,
|
||||
updaterSettings
|
||||
);
|
||||
} catch (IOException e) {
|
||||
plugin.getPluginLogger().severe("Failed to load config " + filePath, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlDocument loadData(File file) {
|
||||
try (InputStream inputStream = new FileInputStream(file)) {
|
||||
@@ -420,7 +492,7 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
}
|
||||
}
|
||||
|
||||
protected Path resolveConfig(String filePath) {
|
||||
public Path resolveConfig(String filePath) {
|
||||
if (filePath == null || filePath.isEmpty()) {
|
||||
throw new IllegalArgumentException("ResourcePath cannot be null or empty");
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package net.momirealms.customnameplates.api;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.momirealms.customnameplates.api.feature.actionbar.ActionBarManager;
|
||||
import net.momirealms.customnameplates.api.feature.advance.AdvanceManager;
|
||||
import net.momirealms.customnameplates.api.feature.background.BackgroundManager;
|
||||
@@ -27,6 +29,7 @@ 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.helper.VersionHelper;
|
||||
import net.momirealms.customnameplates.api.network.PacketSender;
|
||||
import net.momirealms.customnameplates.api.network.PipelineInjector;
|
||||
import net.momirealms.customnameplates.api.placeholder.PlaceholderManager;
|
||||
@@ -39,8 +42,6 @@ import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
|
||||
import net.momirealms.customnameplates.common.plugin.scheduler.SchedulerTask;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
@@ -66,10 +67,10 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
protected BossBarManager bossBarManager;
|
||||
protected UnlimitedTagManager unlimitedTagManager;
|
||||
protected Platform platform;
|
||||
protected MainTask mainTask = new MainTask(this);
|
||||
protected MainTask mainTask;
|
||||
protected SchedulerTask scheduledMainTask;
|
||||
protected ConcurrentHashMap<UUID, CNPlayer> onlinePlayerMap = new ConcurrentHashMap<>();
|
||||
protected HashMap<Integer, CNPlayer> entityIDFastLookup = new HashMap<>();
|
||||
protected Int2ObjectOpenHashMap<CNPlayer> entityIDFastLookup = new Int2ObjectOpenHashMap<>();
|
||||
protected AdvanceManager advanceManager;
|
||||
protected BackgroundManager backgroundManager;
|
||||
protected EventManager eventManager;
|
||||
@@ -79,6 +80,14 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
protected ImageManager imageManager;
|
||||
protected NameplateManager nameplateManager;
|
||||
protected ResourcePackManager resourcePackManager;
|
||||
protected CustomNameplatesAPI api;
|
||||
|
||||
private String buildByBit = "%%__BUILTBYBIT__%%";
|
||||
private String polymart = "%%__POLYMART__%%";
|
||||
private String time = "%%__TIMESTAMP__%%";
|
||||
private String user = "%%__USER__%%";
|
||||
private String username = "%%__USERNAME__%%";
|
||||
private boolean isLatest = false;
|
||||
|
||||
protected CustomNameplates() {
|
||||
instance = this;
|
||||
@@ -96,6 +105,36 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
@Override
|
||||
public abstract void disable();
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
boolean downloadFromPolymart = polymart.equals("1");
|
||||
boolean downloadFromBBB = buildByBit.equals("true");
|
||||
if (ConfigManager.checkUpdate()) {
|
||||
VersionHelper.UPDATE_CHECKER.apply(this).thenAccept(result -> {
|
||||
String link;
|
||||
if (downloadFromPolymart) {
|
||||
link = "https://polymart.org/resource/2543/";
|
||||
} else if (downloadFromBBB) {
|
||||
link = "https://builtbybit.com/resources/36359/";
|
||||
} else {
|
||||
link = "https://github.com/Xiao-MoMi/Custom-Nameplates/";
|
||||
}
|
||||
if (!result) {
|
||||
this.getPluginLogger().info("You are using the latest version.");
|
||||
isLatest = true;
|
||||
} else {
|
||||
this.getPluginLogger().warn("Update is available: " + link);
|
||||
isLatest = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpToDate() {
|
||||
return isLatest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs debug messages through the provided supplier.
|
||||
*
|
||||
@@ -204,6 +243,7 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
*
|
||||
* @return the {@link EventManager} instance
|
||||
*/
|
||||
@Override
|
||||
public EventManager getEventManager() {
|
||||
return eventManager;
|
||||
}
|
||||
@@ -262,6 +302,15 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
return resourcePackManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API class
|
||||
*
|
||||
* @return api
|
||||
*/
|
||||
public CustomNameplatesAPI getAPI() {
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform object for accessing platform-specific functionality.
|
||||
*
|
||||
@@ -277,7 +326,7 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
* @return a collection of {@link CNPlayer} instances
|
||||
*/
|
||||
public Collection<CNPlayer> getOnlinePlayers() {
|
||||
return new HashSet<>(onlinePlayerMap.values());
|
||||
return new ObjectArrayList<>(onlinePlayerMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.api;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
|
||||
import net.momirealms.customnameplates.api.feature.OffsetFont;
|
||||
import net.momirealms.customnameplates.api.feature.background.Background;
|
||||
import net.momirealms.customnameplates.api.feature.bubble.Bubble;
|
||||
import net.momirealms.customnameplates.api.feature.nameplate.Nameplate;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
import net.momirealms.customnameplates.api.placeholder.internal.StaticPosition;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public record CustomNameplatesAPI(CustomNameplates plugin) {
|
||||
|
||||
private static CustomNameplatesAPI instance;
|
||||
|
||||
public CustomNameplatesAPI(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CustomNameplates plugin instance.
|
||||
*
|
||||
* @return the CustomNameplates plugin
|
||||
*/
|
||||
@Override
|
||||
public CustomNameplates plugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a player by their UUID.
|
||||
*
|
||||
* @param uuid the player's UUID
|
||||
* @return the CNPlayer object if found, otherwise null
|
||||
*/
|
||||
@Nullable
|
||||
public CNPlayer getPlayer(UUID uuid) {
|
||||
return plugin.getPlayer(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a Background by its ID.
|
||||
*
|
||||
* @param id the background ID
|
||||
* @return an Optional containing the Background if found, or empty if not
|
||||
*/
|
||||
@NotNull
|
||||
public Optional<Background> getBackground(@NotNull String id) {
|
||||
return Optional.ofNullable(plugin.getBackgroundManager().backgroundById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a Nameplate by its ID.
|
||||
*
|
||||
* @param id the nameplate ID
|
||||
* @return an Optional containing the Nameplate if found, or empty if not
|
||||
*/
|
||||
@NotNull
|
||||
public Optional<Nameplate> getNameplate(@NotNull String id) {
|
||||
return Optional.ofNullable(plugin.getNameplateManager().nameplateById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a Bubble by its ID.
|
||||
*
|
||||
* @param id the bubble ID
|
||||
* @return an Optional containing the Bubble if found, or empty if not
|
||||
*/
|
||||
@NotNull
|
||||
public Optional<Bubble> getBubble(@NotNull String id) {
|
||||
return Optional.ofNullable(plugin.getBubbleManager().bubbleById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text string with an image, applying margins around the image.
|
||||
*
|
||||
* @param text the text to be displayed
|
||||
* @param adaptiveImage the image to insert with the text
|
||||
* @param leftMargin the margin to apply on the left of the image
|
||||
* @param rightMargin the margin to apply on the right of the image
|
||||
* @return the resulting string with the image and margins
|
||||
*/
|
||||
@NotNull
|
||||
public String createTextWithImage(@NotNull String text, @NotNull AdaptiveImage adaptiveImage, float leftMargin, float rightMargin) {
|
||||
if (AdventureHelper.legacySupport) {
|
||||
text = AdventureHelper.legacyToMiniMessage(text);
|
||||
}
|
||||
float advance = plugin.getAdvanceManager().getLineAdvance(text);
|
||||
return adaptiveImage.createImagePrefix(advance, leftMargin, rightMargin) + text + adaptiveImage.createImageSuffix(advance, leftMargin, rightMargin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width advance (text length in visual representation) for a given text.
|
||||
*
|
||||
* @param text the text to measure
|
||||
* @return the advance width of the text
|
||||
*/
|
||||
public float getTextAdvance(@NotNull String text) {
|
||||
return plugin.getAdvanceManager().getLineAdvance(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a statically positioned text, aligning it to the left, right, or middle
|
||||
* of the specified width.
|
||||
*
|
||||
* @param text the text to be positioned
|
||||
* @param width the total width for the text positioning
|
||||
* @param position the desired static position (LEFT, RIGHT, MIDDLE)
|
||||
* @return the resulting string with the appropriate positioning
|
||||
*/
|
||||
@NotNull
|
||||
public String createStaticText(@NotNull String text, int width, @NotNull StaticPosition position) {
|
||||
float parsedWidth = CustomNameplates.getInstance().getAdvanceManager().getLineAdvance(text);
|
||||
switch (position) {
|
||||
case LEFT -> {
|
||||
return text + AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth));
|
||||
}
|
||||
case RIGHT -> {
|
||||
return AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)) + text;
|
||||
}
|
||||
case MIDDLE -> {
|
||||
int half = (int) ((width - parsedWidth) / 2);
|
||||
String left = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(half));
|
||||
String right = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth - half));
|
||||
return left + text + right;
|
||||
}
|
||||
default -> {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of CustomNameplatesAPI.
|
||||
* Throws an exception if the API has not been initialized.
|
||||
*
|
||||
* @return the CustomNameplatesAPI instance
|
||||
*/
|
||||
public static CustomNameplatesAPI getInstance() {
|
||||
if (instance == null) {
|
||||
throw new RuntimeException("Nameplates API has not been initialized yet.");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,9 @@
|
||||
|
||||
package net.momirealms.customnameplates.api;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -29,10 +30,11 @@ public class MainTask implements Runnable {
|
||||
|
||||
private static final Map<Integer, Integer> TIME_1 = new ConcurrentHashMap<>(2048);
|
||||
private static final Map<Integer, Integer> TIME_2 = new ConcurrentHashMap<>(2048);
|
||||
private static final Set<Integer> requestedSharedPlaceholders = Collections.synchronizedSet(new HashSet<>());
|
||||
private static final Set<Integer> requestedSharedPlaceholders = Collections.synchronizedSet(new ObjectOpenHashSet<>());
|
||||
private int timer;
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private boolean state;
|
||||
|
||||
public MainTask(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -52,24 +54,31 @@ public class MainTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
RUN_TICKS++;
|
||||
requestedSharedPlaceholders.clear();
|
||||
long time1 = System.nanoTime();
|
||||
plugin.actionBarManager.refreshConditions();
|
||||
plugin.bossBarManager.onTick();
|
||||
plugin.unlimitedTagManager.onTick();
|
||||
long time2 = System.nanoTime();
|
||||
plugin.placeholderManager.refreshPlaceholders();
|
||||
long time3 = System.nanoTime();
|
||||
plugin.actionBarManager.checkHeartBeats();
|
||||
int diff1 = (int) (time2 - time1);
|
||||
TIME_1.put(timer, diff1);
|
||||
int diff2 = (int) (time3 - time2);
|
||||
TIME_2.put(timer, diff2);
|
||||
timer++;
|
||||
if (timer >= 1200) timer = 0;
|
||||
if (RUN_TICKS < 0) {
|
||||
CustomNameplates.getInstance().reload();
|
||||
// we should skip the task if the server is heavily loaded
|
||||
if (this.state) return;
|
||||
this.state = true;
|
||||
try {
|
||||
RUN_TICKS++;
|
||||
requestedSharedPlaceholders.clear();
|
||||
long time1 = System.nanoTime();
|
||||
plugin.actionBarManager.refreshConditions();
|
||||
plugin.bossBarManager.onTick();
|
||||
plugin.unlimitedTagManager.onTick();
|
||||
long time2 = System.nanoTime();
|
||||
plugin.placeholderManager.refreshPlaceholders();
|
||||
long time3 = System.nanoTime();
|
||||
plugin.actionBarManager.checkHeartBeats();
|
||||
int diff1 = (int) (time2 - time1);
|
||||
TIME_1.put(timer, diff1);
|
||||
int diff2 = (int) (time3 - time2);
|
||||
TIME_2.put(timer, diff2);
|
||||
timer++;
|
||||
if (timer >= 1200) timer = 0;
|
||||
if (RUN_TICKS < 0) {
|
||||
CustomNameplates.getInstance().reload();
|
||||
}
|
||||
} finally {
|
||||
this.state = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,4 +222,15 @@ public interface Platform {
|
||||
* @return the remove entity packet object
|
||||
*/
|
||||
Object removeEntityPacket(int... entityID);
|
||||
|
||||
/**
|
||||
* Gets the biome based on location
|
||||
*
|
||||
* @param world world
|
||||
* @param x x
|
||||
* @param y y
|
||||
* @param z z
|
||||
* @return the biome key
|
||||
*/
|
||||
String getBiome(String world, int x, int y, int z);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customnameplates.api.feature;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
|
||||
/**
|
||||
* Listener for handling player actions
|
||||
*/
|
||||
public interface PlayerListener {
|
||||
|
||||
/**
|
||||
* Called when a player changes the world
|
||||
*
|
||||
* @param player the player who changes the world
|
||||
*/
|
||||
void onChangeWorld(CNPlayer player);
|
||||
|
||||
/**
|
||||
* Called when a player respawns
|
||||
*
|
||||
* @param player the player who respawns
|
||||
*/
|
||||
void onRespawn(CNPlayer player);
|
||||
|
||||
/**
|
||||
* Called when a player teleports
|
||||
*
|
||||
* @param player the player who respawns
|
||||
*/
|
||||
void onTeleport(CNPlayer player);
|
||||
}
|
||||
+20
-12
@@ -17,29 +17,31 @@
|
||||
|
||||
package net.momirealms.customnameplates.api.feature;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
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.Objects;
|
||||
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 final List<Function<CNPlayer, Function<CNPlayer, String>>> textFunctions = new ObjectArrayList<>();
|
||||
private final Set<Placeholder> set = new ObjectOpenHashSet<>();
|
||||
private boolean init = false;
|
||||
|
||||
public PreParsedDynamicText(String text) {
|
||||
this.text = text;
|
||||
this.text = Objects.requireNonNull(text);
|
||||
}
|
||||
|
||||
public PreParsedDynamicText(String text, boolean init) {
|
||||
this.text = text;
|
||||
this.text = Objects.requireNonNull(text);
|
||||
if (init) init();
|
||||
}
|
||||
|
||||
@@ -53,18 +55,24 @@ public class PreParsedDynamicText {
|
||||
for (String id : detectedPlaceholders) {
|
||||
Placeholder placeholder = manager.getPlaceholder(id);
|
||||
placeholders.add(placeholder);
|
||||
if (placeholder instanceof RelationalPlaceholder) {
|
||||
convertor.add((owner) -> (viewer) -> owner.getRelationalData(placeholder, viewer));
|
||||
if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
convertor.add((owner) -> (viewer) -> owner.getCachedRelationalValue(relationalPlaceholder, viewer));
|
||||
} else if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
|
||||
convertor.add((owner) -> (viewer) -> {
|
||||
if (owner != null) {
|
||||
return owner.getData(placeholder);
|
||||
return owner.getCachedPlayerValue(playerPlaceholder);
|
||||
} else {
|
||||
return playerPlaceholder.request(null);
|
||||
}
|
||||
});
|
||||
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
|
||||
convertor.add((owner) -> (viewer) -> sharedPlaceholder.getLatestValue());
|
||||
convertor.add((owner) -> (viewer) -> {
|
||||
if (owner != null) {
|
||||
return owner.getCachedSharedValue(sharedPlaceholder);
|
||||
} else {
|
||||
return sharedPlaceholder.request();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
convertor.add((owner) -> (viewer) -> id);
|
||||
}
|
||||
@@ -89,12 +97,12 @@ public class PreParsedDynamicText {
|
||||
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));
|
||||
// To optimize the tree height
|
||||
set.addAll(new ObjectArrayList<>(placeholders));
|
||||
}
|
||||
|
||||
public DynamicText fastCreate(CNPlayer player) {
|
||||
List<Function<CNPlayer, String>> functions = new ArrayList<>();
|
||||
List<Function<CNPlayer, String>> functions = new ObjectArrayList<>();
|
||||
for (Function<CNPlayer, Function<CNPlayer, String>> textFunction : textFunctions) {
|
||||
functions.add(textFunction.apply(player));
|
||||
}
|
||||
|
||||
+9
-2
@@ -25,7 +25,7 @@ import net.momirealms.customnameplates.api.MainTask;
|
||||
*
|
||||
* @param <D> the type of data being stored
|
||||
*/
|
||||
public class TickStampData<D> {
|
||||
public class TimeStampData<D> {
|
||||
|
||||
private D data;
|
||||
private int packedTicks;
|
||||
@@ -37,7 +37,7 @@ public class TickStampData<D> {
|
||||
* @param ticks the number of ticks to store
|
||||
* @param changed whether the value has changed
|
||||
*/
|
||||
public TickStampData(D data, int ticks, boolean changed) {
|
||||
public TimeStampData(D data, int ticks, boolean changed) {
|
||||
this.data = data;
|
||||
this.packedTicks = packBooleanAndTicks(changed, ticks);
|
||||
}
|
||||
@@ -60,6 +60,13 @@ public class TickStampData<D> {
|
||||
this.packedTicks = packBooleanAndTicks(changed, MainTask.getTicks());
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume the flag
|
||||
*/
|
||||
public void resetChangedFlag() {
|
||||
this.packedTicks = packedTicks & 0x7FFFFFFF;;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stored data.
|
||||
*
|
||||
+4
-4
@@ -18,8 +18,8 @@
|
||||
package net.momirealms.customnameplates.api.feature.advance;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
@@ -28,11 +28,11 @@ import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class CharacterFontAdvanceDataImpl implements CharacterFontAdvanceData {
|
||||
|
||||
private final HashMap<Integer, Float> data;
|
||||
private final Map<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) {
|
||||
public CharacterFontAdvanceDataImpl(String id, Map<Integer, Float> data, Function<Map<String, Object>, List<JsonObject>> fontProviderFunction) {
|
||||
this.data = data;
|
||||
this.id = requireNonNull(id);
|
||||
this.fontProviderFunction = requireNonNull(fontProviderFunction);
|
||||
@@ -65,7 +65,7 @@ public class CharacterFontAdvanceDataImpl implements CharacterFontAdvanceData {
|
||||
|
||||
public static class BuilderImpl implements Builder {
|
||||
|
||||
private final HashMap<Integer, Float> data = new HashMap<>();
|
||||
private final Int2FloatOpenHashMap data = new Int2FloatOpenHashMap();
|
||||
private String id;
|
||||
private Function<Map<String, Object>, List<JsonObject>> fontProviderFunction = (stringObjectMap -> null);
|
||||
|
||||
|
||||
+6
-6
@@ -17,18 +17,18 @@
|
||||
|
||||
package net.momirealms.customnameplates.api.feature.advance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
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 Map<Integer, Float> data = new Int2FloatOpenHashMap();
|
||||
private final List<CharacterFontAdvanceData> parents = new ObjectArrayList<>();
|
||||
private final String id;
|
||||
|
||||
public ConfigurableFontAdvanceDataImpl(String id, float defaultAdvance, HashMap<Integer, Float> customData, List<CharacterFontAdvanceData> parentFonts) {
|
||||
|
||||
+38
-35
@@ -119,47 +119,48 @@ public class BackgroundImpl implements Background {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createImagePrefix(float n, float leftMargin, float rightMargin) {
|
||||
String offset1 = OffsetFont.shortestNegChars(n + rightMargin + right.advance());
|
||||
n = leftMargin + n + rightMargin;
|
||||
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
String offset1 = OffsetFont.shortestNegChars(advance + rightMargin + right.advance());
|
||||
advance = leftMargin + advance + rightMargin;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(left.character());
|
||||
while (n >= 128) {
|
||||
while (advance >= 128) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_128.character());
|
||||
n -= 128;
|
||||
advance -= 128;
|
||||
}
|
||||
if (n - 64 >= 0) {
|
||||
if (advance - 64 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_64.character());
|
||||
n -= 64;
|
||||
advance -= 64;
|
||||
}
|
||||
if (n - 32 >= 0) {
|
||||
if (advance - 32 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_32.character());
|
||||
n -= 32;
|
||||
advance -= 32;
|
||||
}
|
||||
if (n - 16 >= 0) {
|
||||
if (advance - 16 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_16.character());
|
||||
n -= 16;
|
||||
advance -= 16;
|
||||
}
|
||||
if (n - 8 >= 0) {
|
||||
if (advance - 8 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_8.character());
|
||||
n -= 8;
|
||||
advance -= 8;
|
||||
}
|
||||
if (n - 4 >= 0) {
|
||||
if (advance - 4 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_4.character());
|
||||
n -= 4;
|
||||
advance -= 4;
|
||||
}
|
||||
if (n - 2 >= 0) {
|
||||
if (advance - 2 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_2.character());
|
||||
n -= 2;
|
||||
advance -= 2;
|
||||
}
|
||||
if (n - 1 >= 0) {
|
||||
if (advance - 1 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_1.character());
|
||||
}
|
||||
@@ -171,50 +172,52 @@ public class BackgroundImpl implements Background {
|
||||
|
||||
@Override
|
||||
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
return OffsetFont.shortestPosChars(rightMargin + right.advance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createImage(float n, float leftMargin, float rightMargin) {
|
||||
n = n + leftMargin + rightMargin + 2;
|
||||
public String createImage(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
advance = advance + leftMargin + rightMargin + 2;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(left.character());
|
||||
while (n >= 128) {
|
||||
while (advance >= 128) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_128.character());
|
||||
n -= 128;
|
||||
advance -= 128;
|
||||
}
|
||||
if (n - 64 >= 0) {
|
||||
if (advance - 64 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_64.character());
|
||||
n -= 64;
|
||||
advance -= 64;
|
||||
}
|
||||
if (n - 32 >= 0) {
|
||||
if (advance - 32 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_32.character());
|
||||
n -= 32;
|
||||
advance -= 32;
|
||||
}
|
||||
if (n - 16 >= 0) {
|
||||
if (advance - 16 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_16.character());
|
||||
n -= 16;
|
||||
advance -= 16;
|
||||
}
|
||||
if (n - 8 >= 0) {
|
||||
if (advance - 8 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_8.character());
|
||||
n -= 8;
|
||||
advance -= 8;
|
||||
}
|
||||
if (n - 4 >= 0) {
|
||||
if (advance - 4 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_4.character());
|
||||
n -= 4;
|
||||
advance -= 4;
|
||||
}
|
||||
if (n - 2 >= 0) {
|
||||
if (advance - 2 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_2.character());
|
||||
n -= 2;
|
||||
advance -= 2;
|
||||
}
|
||||
if (n - 1 >= 0) {
|
||||
if (advance - 1 >= 0) {
|
||||
stringBuilder.append(OffsetFont.NEG_1.character());
|
||||
stringBuilder.append(width_1.character());
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ public class BubbleImpl implements Bubble {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(left.character());
|
||||
sb.append(OffsetFont.NEG_1.character());
|
||||
@@ -110,6 +111,7 @@ public class BubbleImpl implements Bubble {
|
||||
|
||||
@Override
|
||||
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
|
||||
float actualMiddleWidth = 0;
|
||||
actualMiddleWidth += (tail.advance() - 1);
|
||||
@@ -122,6 +124,7 @@ public class BubbleImpl implements Bubble {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public String createImage(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(left.character());
|
||||
sb.append(OffsetFont.NEG_1.character());
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public record Animation(int speed, int frames) {
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
package net.momirealms.customnameplates.api.feature.image;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface Image {
|
||||
|
||||
@@ -33,15 +34,15 @@ public interface Image {
|
||||
*
|
||||
* @return true if the image has a shadow, false otherwise
|
||||
*/
|
||||
boolean hasShadow();
|
||||
boolean removeShadow();
|
||||
|
||||
/**
|
||||
* Returns the opacity level of the image.
|
||||
* The value should typically range from 0 (fully transparent) to 255 (fully opaque).
|
||||
* Get the animation of the image
|
||||
*
|
||||
* @return the opacity value of the image
|
||||
* @return the animated image
|
||||
*/
|
||||
int opacity();
|
||||
@Nullable
|
||||
Animation animation();
|
||||
|
||||
/**
|
||||
* Returns the configured character associated with this image.
|
||||
@@ -73,20 +74,20 @@ public interface Image {
|
||||
Builder id(String id);
|
||||
|
||||
/**
|
||||
* Sets whether the image has a shadow effect.
|
||||
* Sets whether to remove the shadow of the image
|
||||
*
|
||||
* @param has true if the image should have a shadow, false otherwise
|
||||
* @param remove true if to remove the shadow
|
||||
* @return the builder instance
|
||||
*/
|
||||
Builder hasShadow(boolean has);
|
||||
Builder removeShadow(boolean remove);
|
||||
|
||||
/**
|
||||
* Sets the opacity level of the image.
|
||||
* Sets the animation of the image
|
||||
*
|
||||
* @param opacity the opacity value, typically from 0 to 255
|
||||
* @param animation animation
|
||||
* @return the builder instance
|
||||
*/
|
||||
Builder opacity(int opacity);
|
||||
Builder animation(@Nullable Animation animation);
|
||||
|
||||
/**
|
||||
* Sets the configured character associated with this image.
|
||||
|
||||
+17
-16
@@ -18,21 +18,22 @@
|
||||
package net.momirealms.customnameplates.api.feature.image;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ImageImpl implements Image {
|
||||
|
||||
private final String id;
|
||||
private final boolean hasShadow;
|
||||
private final int opacity;
|
||||
private final boolean removeShadow;
|
||||
private final ConfiguredCharacter character;
|
||||
private final Animation animation;
|
||||
|
||||
public ImageImpl(String id, boolean hasShadow, int opacity, ConfiguredCharacter character) {
|
||||
public ImageImpl(String id, boolean removeShadow, Animation animation, ConfiguredCharacter character) {
|
||||
this.id = id;
|
||||
this.hasShadow = hasShadow;
|
||||
this.opacity = opacity;
|
||||
this.removeShadow = removeShadow;
|
||||
this.character = character;
|
||||
this.animation = animation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,13 +42,13 @@ public class ImageImpl implements Image {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasShadow() {
|
||||
return hasShadow;
|
||||
public boolean removeShadow() {
|
||||
return removeShadow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int opacity() {
|
||||
return opacity;
|
||||
public @Nullable Animation animation() {
|
||||
return animation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,9 +72,9 @@ public class ImageImpl implements Image {
|
||||
public static class BuilderImpl implements Builder {
|
||||
|
||||
private String id;
|
||||
private boolean hasShadow;
|
||||
private int opacity;
|
||||
private boolean removeShadow;
|
||||
private ConfiguredCharacter character;
|
||||
private Animation animation;
|
||||
|
||||
@Override
|
||||
public Builder id(String id) {
|
||||
@@ -82,14 +83,14 @@ public class ImageImpl implements Image {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder hasShadow(boolean has) {
|
||||
this.hasShadow = has;
|
||||
public Builder removeShadow(boolean removeShadow) {
|
||||
this.removeShadow = removeShadow;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder opacity(int opacity) {
|
||||
this.opacity = opacity;
|
||||
public Builder animation(@Nullable Animation animation) {
|
||||
this.animation = animation;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ public class ImageImpl implements Image {
|
||||
|
||||
@Override
|
||||
public Image build() {
|
||||
return new ImageImpl(id, hasShadow, opacity, character);
|
||||
return new ImageImpl(id, removeShadow, animation, character);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -57,6 +57,13 @@ public interface Nameplate extends AdaptiveImage {
|
||||
*/
|
||||
ConfiguredCharacter right();
|
||||
|
||||
/**
|
||||
* Gets the min width of the nameplate
|
||||
*
|
||||
* @return the min width of the nameplate
|
||||
*/
|
||||
int minWidth();
|
||||
|
||||
/**
|
||||
* Creates a new builder for constructing a Nameplate configuration.
|
||||
*
|
||||
@@ -87,6 +94,14 @@ public interface Nameplate extends AdaptiveImage {
|
||||
*/
|
||||
Builder displayName(String displayName);
|
||||
|
||||
/**
|
||||
* Sets the min width for the nameplate
|
||||
*
|
||||
* @param minWidth min width
|
||||
* @return the builder instance
|
||||
*/
|
||||
Builder minWidth(int minWidth);
|
||||
|
||||
/**
|
||||
* Sets the configured character for the left side of the nameplate.
|
||||
*
|
||||
|
||||
+22
-2
@@ -29,10 +29,12 @@ public class NameplateImpl implements Nameplate {
|
||||
private final ConfiguredCharacter left;
|
||||
private final ConfiguredCharacter middle;
|
||||
private final ConfiguredCharacter right;
|
||||
private final int minWidth;
|
||||
|
||||
public NameplateImpl(String id, String displayName, ConfiguredCharacter left, ConfiguredCharacter middle, ConfiguredCharacter right) {
|
||||
public NameplateImpl(String id, String displayName, int minWidth, ConfiguredCharacter left, ConfiguredCharacter middle, ConfiguredCharacter right) {
|
||||
this.id = id;
|
||||
this.displayName = displayName;
|
||||
this.minWidth = minWidth;
|
||||
this.left = left;
|
||||
this.middle = middle;
|
||||
this.right = right;
|
||||
@@ -63,6 +65,11 @@ public class NameplateImpl implements Nameplate {
|
||||
return right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int minWidth() {
|
||||
return minWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) return true;
|
||||
@@ -79,6 +86,8 @@ public class NameplateImpl implements Nameplate {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
advance = Math.max(minWidth, advance);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(left.character());
|
||||
sb.append(OffsetFont.NEG_1.character());
|
||||
@@ -97,6 +106,8 @@ public class NameplateImpl implements Nameplate {
|
||||
|
||||
@Override
|
||||
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
advance = Math.max(minWidth, advance);
|
||||
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());
|
||||
@@ -105,6 +116,8 @@ public class NameplateImpl implements Nameplate {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public String createImage(float advance, float leftMargin, float rightMargin) {
|
||||
if (advance <= 0) return "";
|
||||
advance = Math.max(minWidth, advance);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(left.character());
|
||||
sb.append(OffsetFont.NEG_1.character());
|
||||
@@ -128,6 +141,7 @@ public class NameplateImpl implements Nameplate {
|
||||
private ConfiguredCharacter left;
|
||||
private ConfiguredCharacter middle;
|
||||
private ConfiguredCharacter right;
|
||||
private int minWidth;
|
||||
|
||||
@Override
|
||||
public Builder id(String id) {
|
||||
@@ -141,6 +155,12 @@ public class NameplateImpl implements Nameplate {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder minWidth(int minWidth) {
|
||||
this.minWidth = minWidth;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder left(ConfiguredCharacter left) {
|
||||
this.left = left;
|
||||
@@ -161,7 +181,7 @@ public class NameplateImpl implements Nameplate {
|
||||
|
||||
@Override
|
||||
public Nameplate build() {
|
||||
return new NameplateImpl(id, displayName, left, middle, right);
|
||||
return new NameplateImpl(id, displayName, minWidth, left, middle, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-11
@@ -76,6 +76,7 @@ public abstract class AbstractTag implements Tag {
|
||||
|
||||
@Override
|
||||
public void show(CNPlayer viewer) {
|
||||
if (!renderer.isValid()) return;
|
||||
if (!isShown()) throw new IllegalStateException("This tag is currently hidden");
|
||||
viewers.add(viewer);
|
||||
resetViewerArray();
|
||||
@@ -95,7 +96,8 @@ public abstract class AbstractTag implements Tag {
|
||||
@Override
|
||||
public void hide(CNPlayer viewer) {
|
||||
if (!isShown()) return;
|
||||
viewers.remove(viewer);
|
||||
boolean removed = viewers.remove(viewer);
|
||||
if (!removed) return;
|
||||
resetViewerArray();
|
||||
owner.untrackPassengers(viewer, entityID);
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID);
|
||||
@@ -118,15 +120,15 @@ public abstract class AbstractTag implements Tag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerCrouching(boolean isCrouching) {
|
||||
public void darkTag(boolean dark) {
|
||||
for (CNPlayer viewer : viewerArray) {
|
||||
onPlayerCrouching(viewer, isCrouching);
|
||||
darkTag(viewer, dark);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerCrouching(CNPlayer viewer, boolean isCrouching) {
|
||||
Consumer<List<Object>> modifiers = CustomNameplates.getInstance().getPlatform().createOpacityModifier(isCrouching ? 64 : opacity());
|
||||
public void darkTag(CNPlayer viewer, boolean dark) {
|
||||
Consumer<List<Object>> modifiers = CustomNameplates.getInstance().getPlatform().createOpacityModifier(dark ? 64 : opacity());
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifiers));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
|
||||
}
|
||||
@@ -149,12 +151,17 @@ public abstract class AbstractTag implements Tag {
|
||||
@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);
|
||||
}
|
||||
updateTranslation(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTranslation(CNPlayer viewer) {
|
||||
Tracker tracker = owner.getTracker(viewer);
|
||||
if (tracker != null) {
|
||||
Consumer<List<Object>> modifier = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(viewer).multiply(tracker.getScale()));
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,13 @@ public interface NameTagConfig {
|
||||
*/
|
||||
boolean affectedByScaling();
|
||||
|
||||
/**
|
||||
* Checks if the name tag is affected by spectator mode.
|
||||
*
|
||||
* @return true if affected by spectator mode, false otherwise
|
||||
*/
|
||||
boolean affectedBySpectator();
|
||||
|
||||
/**
|
||||
* Returns the alignment of the name tag.
|
||||
*
|
||||
@@ -300,6 +307,14 @@ public interface NameTagConfig {
|
||||
*/
|
||||
Builder affectedByCrouching(boolean affectedByCrouching);
|
||||
|
||||
/**
|
||||
* Sets whether the name tag is affected by spectator mode.
|
||||
*
|
||||
* @param affectedBySpectator true if the name tag is affected by spectator mode, false otherwise
|
||||
* @return the builder instance
|
||||
*/
|
||||
Builder affectedBySpectator(boolean affectedBySpectator);
|
||||
|
||||
/**
|
||||
* Sets whether the name tag is affected by scaling.
|
||||
*
|
||||
|
||||
+16
-2
@@ -42,8 +42,9 @@ public class NameTagConfigImpl implements NameTagConfig {
|
||||
private final Vector3 translation;
|
||||
private final boolean affectedByCrouching;
|
||||
private final boolean affectedByScale;
|
||||
private final boolean affectedBySpectator;
|
||||
|
||||
public NameTagConfigImpl(String id, Requirement[] ownerRequirements, Requirement[] viewerRequirements, CarouselText[] carouselTexts, int lineWidth, byte opacity, int backgroundColor, boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment, float viewRange, float shadowRadius, float shadowStrength, Vector3 scale, Vector3 translation, boolean affectedByCrouching, boolean affectedByScale) {
|
||||
public NameTagConfigImpl(String id, Requirement[] ownerRequirements, Requirement[] viewerRequirements, CarouselText[] carouselTexts, int lineWidth, byte opacity, int backgroundColor, boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment, float viewRange, float shadowRadius, float shadowStrength, Vector3 scale, Vector3 translation, boolean affectedByCrouching, boolean affectedByScale, boolean affectedBySpectator) {
|
||||
this.id = id;
|
||||
this.ownerRequirements = ownerRequirements;
|
||||
this.viewerRequirements = viewerRequirements;
|
||||
@@ -62,6 +63,7 @@ public class NameTagConfigImpl implements NameTagConfig {
|
||||
this.lineWidth = lineWidth;
|
||||
this.affectedByCrouching = affectedByCrouching;
|
||||
this.affectedByScale = affectedByScale;
|
||||
this.affectedBySpectator = affectedBySpectator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,6 +121,11 @@ public class NameTagConfigImpl implements NameTagConfig {
|
||||
return affectedByScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedBySpectator() {
|
||||
return affectedBySpectator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alignment alignment() {
|
||||
return alignment;
|
||||
@@ -173,6 +180,7 @@ public class NameTagConfigImpl implements NameTagConfig {
|
||||
private Vector3 translation;
|
||||
private boolean affectedByCrouching;
|
||||
private boolean affectedByScale;
|
||||
private boolean affectedBySpectator;
|
||||
|
||||
@Override
|
||||
public Builder id(String id) {
|
||||
@@ -276,6 +284,12 @@ public class NameTagConfigImpl implements NameTagConfig {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder affectedBySpectator(boolean affectedBySpectator) {
|
||||
this.affectedBySpectator = affectedBySpectator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder affectedByScaling(boolean affectedByScale) {
|
||||
this.affectedByScale = affectedByScale;
|
||||
@@ -284,7 +298,7 @@ public class NameTagConfigImpl implements NameTagConfig {
|
||||
|
||||
@Override
|
||||
public NameTagConfig build() {
|
||||
return new NameTagConfigImpl(id, ownerRequirements, viewerRequirements, carouselTexts, lineWidth, opacity, backgroundColor, hasShadow, isSeeThrough, useDefaultBackgroundColor, alignment, viewRange, shadowRadius, shadowStrength, scale, translation, affectedByCrouching, affectedByScale);
|
||||
return new NameTagConfigImpl(id, ownerRequirements, viewerRequirements, carouselTexts, lineWidth, opacity, backgroundColor, hasShadow, isSeeThrough, useDefaultBackgroundColor, alignment, viewRange, shadowRadius, shadowStrength, scale, translation, affectedByCrouching, affectedByScale, affectedBySpectator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,8 @@ public interface Tag {
|
||||
*/
|
||||
boolean affectedByScaling();
|
||||
|
||||
boolean affectedBySpectator();
|
||||
|
||||
/**
|
||||
* Hides the tag for all viewers.
|
||||
*/
|
||||
@@ -151,19 +153,19 @@ public interface Tag {
|
||||
double getTextHeight(CNPlayer viewer);
|
||||
|
||||
/**
|
||||
* Updates the tag state when the player crouches.
|
||||
* Sets the dark mode for the tag.
|
||||
*
|
||||
* @param isCrouching true if the player is crouching, false otherwise
|
||||
* @param dark whether the tag should be dark
|
||||
*/
|
||||
void onPlayerCrouching(boolean isCrouching);
|
||||
void darkTag(boolean dark);
|
||||
|
||||
/**
|
||||
* Updates the tag state when the player crouches for a specific viewer.
|
||||
* Sets the dark mode for the tag for a specific viewer.
|
||||
*
|
||||
* @param viewer the player to update
|
||||
* @param isCrouching true if the player is crouching, false otherwise
|
||||
* @param viewer the player for whom the dark mode should be applied
|
||||
* @param dark whether the tag should be dark for the specific viewer
|
||||
*/
|
||||
void onPlayerCrouching(CNPlayer viewer, boolean isCrouching);
|
||||
void darkTag(CNPlayer viewer, boolean dark);
|
||||
|
||||
/**
|
||||
* Updates the tag scale when the player's scale changes.
|
||||
@@ -185,6 +187,11 @@ public interface Tag {
|
||||
*/
|
||||
void updateTranslation();
|
||||
|
||||
/**
|
||||
* Updates the translation of the tag for a certain player
|
||||
*/
|
||||
void updateTranslation(CNPlayer viewer);
|
||||
|
||||
/**
|
||||
* Returns the scaling vector of the tag for a specific viewer.
|
||||
*
|
||||
@@ -200,4 +207,11 @@ public interface Tag {
|
||||
* @return the translation vector
|
||||
*/
|
||||
Vector3 translation(CNPlayer viewer);
|
||||
|
||||
/**
|
||||
* Returns if the tag has a relative translation
|
||||
*
|
||||
* @return has or not
|
||||
*/
|
||||
boolean relativeTranslation();
|
||||
}
|
||||
@@ -35,6 +35,13 @@ public interface TagRenderer {
|
||||
*/
|
||||
void hatOffset(double hatOffset);
|
||||
|
||||
/**
|
||||
* Checks if the tag is valid
|
||||
*
|
||||
* @return valid or not
|
||||
*/
|
||||
boolean isValid();
|
||||
|
||||
/**
|
||||
* Called every tick to update the state of the tags managed by this renderer.
|
||||
*/
|
||||
|
||||
@@ -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 it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class TeamView {
|
||||
|
||||
private final Map<String, Set<String>> teamMembers = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
@Nullable
|
||||
public Set<String> getTeamMembers(String team) {
|
||||
return teamMembers.get(team);
|
||||
}
|
||||
|
||||
public void addTeamMembers(String team, Collection<String> members) {
|
||||
teamMembers.computeIfAbsent(team, k -> new ObjectOpenHashSet<>(members));
|
||||
}
|
||||
|
||||
public void removeTeamMembers(String team, Collection<String> members) {
|
||||
Set<String> membersSet = teamMembers.get(team);
|
||||
if (membersSet != null) {
|
||||
membersSet.removeAll(members);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTeam(String team) {
|
||||
this.teamMembers.remove(team);
|
||||
}
|
||||
}
|
||||
+19
-1
@@ -57,7 +57,15 @@ public interface UnlimitedTagManager extends Reloadable {
|
||||
* @param player the player to update
|
||||
* @param preview true to enable preview mode, false to disable
|
||||
*/
|
||||
void setPreviewing(CNPlayer player, boolean preview);
|
||||
void setTempPreviewing(CNPlayer player, boolean preview);
|
||||
|
||||
/**
|
||||
* Sets whether a player can always see their tags
|
||||
*
|
||||
* @param player the player to update
|
||||
* @param preview true to enable preview mode, false to disable
|
||||
*/
|
||||
void togglePreviewing(CNPlayer player, boolean preview);
|
||||
|
||||
/**
|
||||
* Returns the duration (in ticks) for which a tag preview is shown.
|
||||
@@ -112,4 +120,14 @@ public interface UnlimitedTagManager extends Reloadable {
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
void onPlayerAttributeSet(CNPlayer owner, CNPlayer viewer, double scale);
|
||||
|
||||
/**
|
||||
* Internal method for updating a player's game mode
|
||||
*
|
||||
* @param owner the player who owns the tags
|
||||
* @param viewer the player viewing the tags
|
||||
* @param isSpectator true if the player is a spectator, false otherwise
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
void onPlayerGameModeChange(CNPlayer owner, CNPlayer viewer, boolean isSpectator);
|
||||
}
|
||||
@@ -84,6 +84,14 @@ public class AdventureHelper {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
AdventureHelper instance = getInstance();
|
||||
instance.miniMessageToMinecraftComponentCache.cleanUp();
|
||||
instance.miniMessageToComponentCache.cleanUp();
|
||||
instance.jsonToMiniMessageCache.cleanUp();
|
||||
instance.minecraftComponentToMiniMessageCache.cleanUp();
|
||||
}
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final AdventureHelper INSTANCE = new AdventureHelper();
|
||||
}
|
||||
@@ -291,7 +299,7 @@ public class AdventureHelper {
|
||||
case 'd' -> stringBuilder.append("<light_purple>");
|
||||
case 'e' -> stringBuilder.append("<yellow>");
|
||||
case 'f' -> stringBuilder.append("<white>");
|
||||
case 'r' -> stringBuilder.append("<r><!i>");
|
||||
case 'r' -> stringBuilder.append("<reset>");
|
||||
case 'l' -> stringBuilder.append("<b>");
|
||||
case 'm' -> stringBuilder.append("<st>");
|
||||
case 'o' -> stringBuilder.append("<i>");
|
||||
|
||||
@@ -61,12 +61,18 @@ public class VersionHelper {
|
||||
private static float version;
|
||||
private static boolean mojmap;
|
||||
private static boolean folia;
|
||||
private static boolean mohist;
|
||||
private static boolean paper;
|
||||
|
||||
public static void init(String serverVersion) {
|
||||
String[] split = serverVersion.split("\\.");
|
||||
version = Float.parseFloat(split[1] + "." + (split.length == 3 ? split[2] : "0"));
|
||||
checkMojMap();
|
||||
checkFolia();
|
||||
checkMohist();
|
||||
checkPaper();
|
||||
boolean isModdedServer = mohist;
|
||||
paper = paper && !isModdedServer;
|
||||
}
|
||||
|
||||
public static float version() {
|
||||
@@ -90,6 +96,26 @@ public class VersionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkMohist() {
|
||||
try {
|
||||
Class.forName("com.mohistmc.api.ServerAPI");
|
||||
mohist = true;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkPaper() {
|
||||
try {
|
||||
Class.forName("com.destroystokyo.paper.Metrics");
|
||||
paper = true;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isVersionNewerThan1_21_2() {
|
||||
return version >= 21.19;
|
||||
}
|
||||
|
||||
public static boolean isVersionNewerThan1_20_5() {
|
||||
return version >= 20.49;
|
||||
}
|
||||
@@ -114,6 +140,14 @@ public class VersionHelper {
|
||||
return folia;
|
||||
}
|
||||
|
||||
public static boolean isMohist() {
|
||||
return mohist;
|
||||
}
|
||||
|
||||
public static boolean isPaperOrItsForks() {
|
||||
return paper;
|
||||
}
|
||||
|
||||
public static boolean isMojmap() {
|
||||
return mojmap;
|
||||
}
|
||||
|
||||
+16
-15
@@ -20,19 +20,33 @@ package net.momirealms.customnameplates.api.network;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Interface for injecting and managing Netty pipeline handlers for players.
|
||||
*/
|
||||
public interface PipelineInjector {
|
||||
|
||||
@ApiStatus.Internal
|
||||
void setUser(Channel channel, CNPlayer user);
|
||||
|
||||
@ApiStatus.Internal
|
||||
CNPlayer getUser(Channel channel);
|
||||
|
||||
@ApiStatus.Internal
|
||||
CNPlayer removeUser(Channel channel);
|
||||
|
||||
@ApiStatus.Internal
|
||||
CNPlayer getUser(Object player);
|
||||
|
||||
/**
|
||||
* Retrieves the Netty channel associated with the specified player.
|
||||
*
|
||||
* @param player the player whose channel is being retrieved
|
||||
* @return the Netty channel associated with the player
|
||||
*/
|
||||
Channel getChannel(CNPlayer player);
|
||||
@ApiStatus.Internal
|
||||
Channel getChannel(Object player);
|
||||
|
||||
/**
|
||||
* Creates a custom ChannelDuplexHandler for the specified player, used to intercept and modify network traffic.
|
||||
@@ -40,19 +54,6 @@ public interface PipelineInjector {
|
||||
* @param player the player for whom the handler is being created
|
||||
* @return a ChannelDuplexHandler for the player
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
ChannelDuplexHandler createHandler(CNPlayer player);
|
||||
|
||||
/**
|
||||
* Injects a custom handler into the player's network channel, allowing interception and modification of packets.
|
||||
*
|
||||
* @param player the player whose channel will be injected
|
||||
*/
|
||||
void inject(CNPlayer player);
|
||||
|
||||
/**
|
||||
* Removes the custom handler from the player's network channel.
|
||||
*
|
||||
* @param player the player whose channel will have the handler removed
|
||||
*/
|
||||
void uninject(CNPlayer player);
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
package net.momirealms.customnameplates.api.network;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@@ -27,6 +27,7 @@ public class Tracker {
|
||||
|
||||
private boolean isCrouching;
|
||||
private double scale;
|
||||
private boolean isSpectator;
|
||||
private final CNPlayer tracker;
|
||||
|
||||
private final CopyOnWriteArrayList<Integer> passengerIDs = new CopyOnWriteArrayList<>();
|
||||
@@ -54,6 +55,14 @@ public class Tracker {
|
||||
isCrouching = crouching;
|
||||
}
|
||||
|
||||
public boolean isSpectator() {
|
||||
return isSpectator;
|
||||
}
|
||||
|
||||
public void setSpectator(boolean spectator) {
|
||||
isSpectator = spectator;
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return scale;
|
||||
}
|
||||
@@ -71,7 +80,7 @@ public class Tracker {
|
||||
}
|
||||
|
||||
public Set<Integer> getPassengerIDs() {
|
||||
return new HashSet<>(passengerIDs);
|
||||
return new ObjectOpenHashSet<>(passengerIDs);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
|
||||
+36
-42
@@ -17,28 +17,21 @@
|
||||
|
||||
package net.momirealms.customnameplates.api.placeholder;
|
||||
|
||||
import java.util.HashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstract base class for placeholders, providing common functionality for managing children, ID, and refresh intervals.
|
||||
*/
|
||||
public abstract class AbstractPlaceholder implements Placeholder {
|
||||
|
||||
protected String id;
|
||||
protected int countId = PlaceholderCounter.getAndIncrease();
|
||||
protected int refreshInterval;
|
||||
protected PlaceholderManager manager;
|
||||
protected Set<Placeholder> children = new HashSet<>();
|
||||
protected Set<Placeholder> children = new ObjectOpenHashSet<>();
|
||||
protected Set<Placeholder> parents = new ObjectOpenHashSet<>();
|
||||
|
||||
/**
|
||||
* Constructs an AbstractPlaceholder with the specified manager, ID, and refresh interval.
|
||||
*
|
||||
* @param manager the PlaceholderManager that manages this placeholder
|
||||
* @param id the ID of the placeholder, must start and end with '%'
|
||||
* @param refreshInterval the refresh interval for the placeholder, 0 will default to -1 (no refresh)
|
||||
*/
|
||||
protected AbstractPlaceholder(PlaceholderManager manager, String id, int refreshInterval) {
|
||||
if (refreshInterval == 0) {
|
||||
refreshInterval = -1;
|
||||
@@ -51,61 +44,62 @@ public abstract class AbstractPlaceholder implements Placeholder {
|
||||
this.refreshInterval = refreshInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique count ID of this placeholder.
|
||||
*
|
||||
* @return the count ID
|
||||
*/
|
||||
@Override
|
||||
public int countId() {
|
||||
return countId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of child placeholders associated with this placeholder.
|
||||
*
|
||||
* @return the set of child placeholders
|
||||
*/
|
||||
@Override
|
||||
public Set<Placeholder> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child placeholder to this placeholder.
|
||||
*
|
||||
* @param placeholder the child placeholder to add
|
||||
*/
|
||||
@Override
|
||||
public void addChild(Placeholder placeholder) {
|
||||
if (placeholder == this) {
|
||||
CustomNameplates.getInstance().getPluginLogger().warn(String.format("There may be something wrong with your configuration. Placeholder relationship level loops. Placeholder %s becomes its own child Placeholder", id));
|
||||
return;
|
||||
}
|
||||
children.add(placeholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple child placeholders to this placeholder.
|
||||
*
|
||||
* @param placeholders the set of child placeholders to add
|
||||
*/
|
||||
@Override
|
||||
public void addChildren(Set<Placeholder> placeholders) {
|
||||
if (placeholders.contains(this)) {
|
||||
CustomNameplates.getInstance().getPluginLogger().warn(String.format("There may be something wrong with your configuration. Placeholder relationship level loops. Placeholder %s becomes its own child Placeholder", id));
|
||||
return;
|
||||
}
|
||||
children.addAll(placeholders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh interval of this placeholder.
|
||||
*
|
||||
* @return the refresh interval
|
||||
*/
|
||||
@Override
|
||||
public void addParent(Placeholder placeholder) {
|
||||
if (placeholder == this) {
|
||||
CustomNameplates.getInstance().getPluginLogger().warn(String.format("There may be something wrong with your configuration. Placeholder relationship level loops. Placeholder %s becomes its own parent Placeholder", id));
|
||||
return;
|
||||
}
|
||||
parents.add(placeholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParents(Set<Placeholder> placeholders) {
|
||||
if (placeholders.contains(this)) {
|
||||
CustomNameplates.getInstance().getPluginLogger().warn(String.format("There may be something wrong with your configuration. Placeholder relationship level loops. Placeholder %s becomes its own parent Placeholder", id));
|
||||
return;
|
||||
}
|
||||
parents.addAll(placeholders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> parents() {
|
||||
return parents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refreshInterval() {
|
||||
return refreshInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of this placeholder.
|
||||
*
|
||||
* @return the placeholder ID
|
||||
*/
|
||||
@Override
|
||||
public String id() {
|
||||
return id;
|
||||
|
||||
+13
-30
@@ -37,59 +37,42 @@ public class DummyPlaceholder implements Placeholder {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing, as DummyPlaceholder does not support adding child placeholders.
|
||||
*
|
||||
* @param placeholder the child placeholder to add
|
||||
*/
|
||||
@Override
|
||||
public void addChild(Placeholder placeholder) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing, as DummyPlaceholder does not support adding multiple child placeholders.
|
||||
*
|
||||
* @param placeholders the set of child placeholders to add
|
||||
*/
|
||||
@Override
|
||||
public void addChildren(Set<Placeholder> placeholders) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty set, as DummyPlaceholder does not have child placeholders.
|
||||
*
|
||||
* @return an empty set of child placeholders
|
||||
*/
|
||||
@Override
|
||||
public void addParent(Placeholder placeholder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParents(Set<Placeholder> placeholders) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> children() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns -1, indicating that this placeholder does not have a refresh interval.
|
||||
*
|
||||
* @return -1, meaning no refresh is needed
|
||||
*/
|
||||
@Override
|
||||
public Set<Placeholder> parents() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refreshInterval() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the DummyPlaceholder.
|
||||
*
|
||||
* @return the placeholder ID
|
||||
*/
|
||||
@Override
|
||||
public String id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique count ID of the DummyPlaceholder.
|
||||
*
|
||||
* @return the count ID
|
||||
*/
|
||||
@Override
|
||||
public int countId() {
|
||||
return counterId;
|
||||
|
||||
@@ -35,6 +35,20 @@ public interface Placeholder {
|
||||
*/
|
||||
void addChildren(Set<Placeholder> placeholders);
|
||||
|
||||
/**
|
||||
* Adds a parent placeholder to this placeholder.
|
||||
*
|
||||
* @param placeholder the parent placeholder to add
|
||||
*/
|
||||
void addParent(Placeholder placeholder);
|
||||
|
||||
/**
|
||||
* Adds multiple parent placeholders to this placeholder.
|
||||
*
|
||||
* @param placeholders the set of parent placeholders to add
|
||||
*/
|
||||
void addParents(Set<Placeholder> placeholders);
|
||||
|
||||
/**
|
||||
* Returns the set of child placeholders associated with this placeholder.
|
||||
*
|
||||
@@ -42,6 +56,13 @@ public interface Placeholder {
|
||||
*/
|
||||
Set<Placeholder> children();
|
||||
|
||||
/**
|
||||
* Returns the set of parent placeholders associated with this placeholder.
|
||||
*
|
||||
* @return the set of parent placeholders
|
||||
*/
|
||||
Set<Placeholder> parents();
|
||||
|
||||
/**
|
||||
* Returns the refresh interval of this placeholder.
|
||||
*
|
||||
|
||||
+9
-1
@@ -37,7 +37,15 @@ public interface PlaceholderManager extends Reloadable {
|
||||
void refreshPlaceholders();
|
||||
|
||||
/**
|
||||
* Gets the refresh interval for a placeholder by its ID.
|
||||
* Gets the refresh interval for a placeholder by its countId.
|
||||
*
|
||||
* @param countId the countId of the placeholder
|
||||
* @return the refresh interval in ticks
|
||||
*/
|
||||
int getRefreshInterval(int countId);
|
||||
|
||||
/**
|
||||
* Gets the refresh interval for a placeholder by its id.
|
||||
*
|
||||
* @param id the ID of the placeholder
|
||||
* @return the refresh interval in ticks
|
||||
|
||||
+2
-21
@@ -18,10 +18,8 @@
|
||||
package net.momirealms.customnameplates.api.placeholder.internal;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.OffsetFont;
|
||||
import net.momirealms.customnameplates.api.CustomNameplatesAPI;
|
||||
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
|
||||
import net.momirealms.customnameplates.api.helper.AdventureHelper;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@@ -62,23 +60,6 @@ public class StaticText {
|
||||
}
|
||||
|
||||
public String create(String text) {
|
||||
float parsedWidth = CustomNameplates.getInstance().getAdvanceManager().getLineAdvance(text);
|
||||
switch (position) {
|
||||
case LEFT -> {
|
||||
return text + AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth));
|
||||
}
|
||||
case RIGHT -> {
|
||||
return AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)) + text;
|
||||
}
|
||||
case MIDDLE -> {
|
||||
int half = (int) ((width - parsedWidth) / 2);
|
||||
String left = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(half));
|
||||
String right = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth - half));
|
||||
return left + text + right;
|
||||
}
|
||||
default -> {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return CustomNameplatesAPI.getInstance().createStaticText(text, width, position);
|
||||
}
|
||||
}
|
||||
+6
@@ -18,6 +18,7 @@
|
||||
package net.momirealms.customnameplates.api.requirement;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
|
||||
/**
|
||||
* A requirement that is always satisfied, representing an "empty" or default requirement.
|
||||
@@ -57,6 +58,11 @@ public class EmptyRequirement implements Requirement {
|
||||
return "empty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countId() {
|
||||
return CustomNameplates.getInstance().getRequirementManager().countId(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns -1, indicating that this requirement does not have a refresh interval.
|
||||
*
|
||||
|
||||
@@ -40,6 +40,13 @@ public interface Requirement {
|
||||
*/
|
||||
String type();
|
||||
|
||||
/**
|
||||
* Returns the int id for faster lookup
|
||||
*
|
||||
* @return count id
|
||||
*/
|
||||
int countId();
|
||||
|
||||
/**
|
||||
* Returns the refresh interval of the requirement.
|
||||
*
|
||||
|
||||
+8
@@ -87,4 +87,12 @@ public interface RequirementManager extends Reloadable {
|
||||
*/
|
||||
@NotNull
|
||||
Requirement parseSimpleRequirement(@NotNull String type, @NotNull Object value);
|
||||
|
||||
/**
|
||||
* Gets the count id for the requirement for faster lookup
|
||||
*
|
||||
* @param requirement requirement
|
||||
* @return the id
|
||||
*/
|
||||
int countId(Requirement requirement);
|
||||
}
|
||||
@@ -21,10 +21,10 @@ public enum StorageType {
|
||||
JSON,
|
||||
YAML,
|
||||
H2,
|
||||
SQLite,
|
||||
MySQL,
|
||||
MariaDB,
|
||||
MongoDB,
|
||||
SQLITE,
|
||||
MYSQL,
|
||||
MARIADB,
|
||||
MONGODB,
|
||||
Redis,
|
||||
NONE
|
||||
}
|
||||
@@ -32,6 +32,9 @@ public class JsonData {
|
||||
@SerializedName("bubble")
|
||||
private String bubble;
|
||||
|
||||
@SerializedName("flags")
|
||||
private int flags;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link JsonData} instance.
|
||||
*
|
||||
@@ -41,6 +44,27 @@ public class JsonData {
|
||||
public JsonData(String nameplate, String bubble) {
|
||||
this.nameplate = nameplate;
|
||||
this.bubble = bubble;
|
||||
this.flags = 0;
|
||||
}
|
||||
|
||||
public JsonData(String nameplate, String bubble, int flags) {
|
||||
this.nameplate = nameplate;
|
||||
this.bubble = bubble;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public JsonData(String nameplate, String bubble, boolean previewState) {
|
||||
this.nameplate = nameplate;
|
||||
this.bubble = bubble;
|
||||
this.flags = encodeFlags(previewState);
|
||||
}
|
||||
|
||||
public static int encodeFlags(boolean previewState) {
|
||||
return previewState ? 1 : 0;
|
||||
}
|
||||
|
||||
public static boolean decodePreviewState(int flags) {
|
||||
return (flags & 1) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +85,15 @@ public class JsonData {
|
||||
return bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags
|
||||
*
|
||||
* @return flags
|
||||
*/
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this JSON data back into a {@link PlayerData} instance.
|
||||
*
|
||||
@@ -72,6 +105,7 @@ public class JsonData {
|
||||
.uuid(uuid)
|
||||
.nameplate(nameplate)
|
||||
.bubble(bubble)
|
||||
.previewTags(decodePreviewState(flags))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,13 @@ public interface PlayerData {
|
||||
*/
|
||||
String bubble();
|
||||
|
||||
/**
|
||||
* Returns if the tag should always be shown to the owner
|
||||
*
|
||||
* @return if the tag should always be shown to the owner
|
||||
*/
|
||||
boolean previewTags();
|
||||
|
||||
/**
|
||||
* Returns the UUID of the player.
|
||||
*
|
||||
@@ -100,6 +107,14 @@ public interface PlayerData {
|
||||
*/
|
||||
Builder uuid(UUID uuid);
|
||||
|
||||
/**
|
||||
* Sets whether to preview state for the {@link PlayerData}.
|
||||
*
|
||||
* @param previewTags the state
|
||||
* @return the builder instance
|
||||
*/
|
||||
Builder previewTags(boolean previewTags);
|
||||
|
||||
/**
|
||||
* Builds and returns the {@link PlayerData} instance.
|
||||
*
|
||||
@@ -114,6 +129,6 @@ public interface PlayerData {
|
||||
* @return a {@link JsonData} object containing the nameplate and bubble data
|
||||
*/
|
||||
default JsonData toJsonData() {
|
||||
return new JsonData(nameplate(), bubble());
|
||||
return new JsonData(nameplate(), bubble(), previewTags());
|
||||
}
|
||||
}
|
||||
+16
-2
@@ -28,11 +28,13 @@ public class PlayerDataImpl implements PlayerData {
|
||||
protected UUID uuid;
|
||||
protected String nameplate;
|
||||
protected String bubble;
|
||||
protected boolean previewTags;
|
||||
|
||||
public PlayerDataImpl(UUID uuid, String nameplate, String bubble) {
|
||||
public PlayerDataImpl(UUID uuid, String nameplate, String bubble, boolean previewTags) {
|
||||
this.uuid = uuid;
|
||||
this.nameplate = nameplate;
|
||||
this.bubble = bubble;
|
||||
this.previewTags = previewTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,6 +47,11 @@ public class PlayerDataImpl implements PlayerData {
|
||||
return bubble;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean previewTags() {
|
||||
return previewTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID uuid() {
|
||||
return uuid;
|
||||
@@ -57,6 +64,7 @@ public class PlayerDataImpl implements PlayerData {
|
||||
|
||||
private String nameplate;
|
||||
private String bubble;
|
||||
private boolean previewTags;
|
||||
private UUID uuid;
|
||||
|
||||
@Override
|
||||
@@ -77,9 +85,15 @@ public class PlayerDataImpl implements PlayerData {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder previewTags(boolean previewTags) {
|
||||
this.previewTags = previewTags;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerData build() {
|
||||
return new PlayerDataImpl(uuid, nameplate, bubble);
|
||||
return new PlayerDataImpl(uuid, nameplate, bubble, previewTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@ plugins {
|
||||
id("io.github.goooler.shadow") version "8.1.8"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":common"))
|
||||
compileOnly(project(":api"))
|
||||
@@ -26,4 +30,6 @@ dependencies {
|
||||
// TTF
|
||||
compileOnly("org.lwjgl:lwjgl-freetype:${rootProject.properties["lwjgl_version"]}")
|
||||
compileOnly("org.lwjgl:lwjgl:${rootProject.properties["lwjgl_version"]}")
|
||||
// Fast util
|
||||
compileOnly("it.unimi.dsi:fastutil:${rootProject.properties["fastutil_version"]}")
|
||||
}
|
||||
+15
-2
@@ -100,10 +100,18 @@ public class ActionBarManagerImpl implements ActionBarManager, JoinQuitListener
|
||||
public void handleActionBarPacket(CNPlayer player, String miniMessage) {
|
||||
ActionBarSender sender = senders.get(player.uuid());
|
||||
if (sender != null) {
|
||||
if (miniMessage.length() >= 1024) return;
|
||||
sender.externalActionBar(miniMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void temporarilyHideCustomActionBar(CNPlayer player) {
|
||||
ActionBarSender sender = senders.get(player.uuid());
|
||||
if (sender != null) {
|
||||
sender.temporarilyHide();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getExternalActionBar(CNPlayer player) {
|
||||
ActionBarSender sender = senders.get(player.uuid());
|
||||
@@ -116,14 +124,19 @@ public class ActionBarManagerImpl implements ActionBarManager, JoinQuitListener
|
||||
@Override
|
||||
public void onPlayerJoin(CNPlayer player) {
|
||||
if (!ConfigManager.actionbarModule()) return;
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
Runnable r = () -> {
|
||||
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);
|
||||
};
|
||||
if (ConfigManager.delaySend() < 0) {
|
||||
r.run();
|
||||
} else {
|
||||
plugin.getScheduler().asyncLater(r, ConfigManager.delaySend() * 50L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+27
-8
@@ -17,7 +17,9 @@
|
||||
|
||||
package net.momirealms.customnameplates.backend.feature.actionbar;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
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.DynamicText;
|
||||
@@ -30,7 +32,6 @@ 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;
|
||||
@@ -48,6 +49,7 @@ public class ActionBarSender implements Feature {
|
||||
|
||||
private String externalActionBar;
|
||||
private long externalExpireTime;
|
||||
private long temporaryHiddenTime;
|
||||
|
||||
private String latestContent;
|
||||
|
||||
@@ -78,7 +80,7 @@ public class ActionBarSender implements Feature {
|
||||
this.onConditionTimerCheck();
|
||||
}
|
||||
|
||||
public void onConditionTimerCheck() {
|
||||
public synchronized void onConditionTimerCheck() {
|
||||
ActionBarConfig[] configs = manager.actionBarConfigs();
|
||||
outer: {
|
||||
for (ActionBarConfig config : configs) {
|
||||
@@ -127,7 +129,7 @@ public class ActionBarSender implements Feature {
|
||||
currentActionBar = carouselText.preParsedDynamicText().fastCreate(owner);
|
||||
|
||||
if (carouselText.updateOnDisplay()) {
|
||||
owner.forceUpdate(currentActionBar.placeholders(), Collections.emptySet());
|
||||
owner.forceUpdatePlaceholders(currentActionBar.placeholders(), Collections.emptySet());
|
||||
}
|
||||
textChangeFlag = true;
|
||||
}
|
||||
@@ -146,14 +148,19 @@ public class ActionBarSender implements Feature {
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
if (currentActionBar == null) {
|
||||
latestContent = "";
|
||||
return;
|
||||
}
|
||||
latestContent = this.currentActionBar.render(owner);
|
||||
textChangeFlag = false;
|
||||
}
|
||||
|
||||
public void sendLatestActionBar() {
|
||||
if (isTemporarilyHidden()) return;
|
||||
if (latestContent != null) {
|
||||
updateLastUpdateTime();
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().setActionBarTextPacket(AdventureHelper.miniMessageToMinecraftComponent(latestContent, "np", "ab"));
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().setActionBarTextPacket(AdventureHelper.miniMessageToMinecraftComponent(latestContent, "nameplates", "actionbar"));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
}
|
||||
}
|
||||
@@ -170,7 +177,7 @@ public class ActionBarSender implements Feature {
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> allPlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
Set<Placeholder> placeholders = new ObjectOpenHashSet<>();
|
||||
for (ActionBarConfig config : manager.actionBarConfigs()) {
|
||||
for (CarouselText text : config.carouselTexts()) {
|
||||
placeholders.addAll(text.preParsedDynamicText().placeholders());
|
||||
@@ -181,8 +188,11 @@ public class ActionBarSender implements Feature {
|
||||
|
||||
@Override
|
||||
public void notifyPlaceholderUpdates(CNPlayer player, boolean force) {
|
||||
refresh();
|
||||
sendLatestActionBar();
|
||||
// The actionbar should be visible before updating
|
||||
if (currentActionBar != null) {
|
||||
refresh();
|
||||
sendLatestActionBar();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateLastUpdateTime() {
|
||||
@@ -204,6 +214,15 @@ public class ActionBarSender implements Feature {
|
||||
public void externalActionBar(@NotNull String externalActionBar) {
|
||||
requireNonNull(externalActionBar);
|
||||
this.externalActionBar = externalActionBar;
|
||||
this.externalExpireTime = System.currentTimeMillis() + 3000;
|
||||
this.externalExpireTime = System.currentTimeMillis() + ConfigManager.otherActionBarStayTime();
|
||||
}
|
||||
|
||||
public void temporarilyHide() {
|
||||
this.temporaryHiddenTime = System.currentTimeMillis() + 3000;
|
||||
}
|
||||
|
||||
public boolean isTemporarilyHidden() {
|
||||
if (!ConfigManager.displaySystemChat()) return false;
|
||||
return temporaryHiddenTime > System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
+29
-6
@@ -25,6 +25,8 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
@@ -292,8 +294,8 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
private final HashMap<String, BiConsumer<String, Section>> templateConfigConsumersMap = new HashMap<>();
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final HashMap<String, CharacterFontAdvanceData> charFontWidthDataMap = new HashMap<>();
|
||||
private final HashMap<String, ConfigurableFontAdvanceData> configFontWidthDataMap = new HashMap<>();
|
||||
private final Object2ObjectOpenHashMap<String, CharacterFontAdvanceData> charFontWidthDataMap = new Object2ObjectOpenHashMap<>();
|
||||
private final Object2ObjectOpenHashMap<String, ConfigurableFontAdvanceData> configFontWidthDataMap = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
private final Cache<String, Float> textWidthCache;
|
||||
|
||||
@@ -520,6 +522,8 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
String codePoints = requireNonNull(section.getString("codepoints", ""), "codepoints should be NonNull");
|
||||
int height = section.getInt("height", 8);
|
||||
boolean custom = section.getBoolean("custom", false);
|
||||
boolean copy = section.getBoolean("generate", false);
|
||||
String namespace = section.getString("namespace", ConfigManager.namespace());
|
||||
|
||||
File bitmapCache = new File(plugin.getDataDirectory().toFile(), "tmp" + File.separator + id + ".tmp");
|
||||
if (!bitmapCache.exists()) {
|
||||
@@ -584,9 +588,25 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
}
|
||||
registerCharacterFontData(id, bitmapCache, (properties) -> {
|
||||
int ascent = (int) properties.get("shift_y");
|
||||
String filePath = custom ? ConfigManager.namespace() + ":font/" + file : "minecraft:font/" + codePoints + ".png";
|
||||
String filePath = custom ? namespace + ":font/" + file : "minecraft:font/" + codePoints + ".png";
|
||||
plugin.getConfigManager().saveResource("tmp/" + codePoints + ".json");
|
||||
StringBuilder jsonContent = new StringBuilder();
|
||||
if (copy) {
|
||||
File pngFile = new File(plugin.getDataDirectory().toFile(), "font" + File.separator + file);
|
||||
File destination = new File(plugin.getDataDirectory().toFile(),
|
||||
"ResourcePack"
|
||||
+ File.separator + "assets"
|
||||
+ File.separator + (custom ? namespace : "minecraft")
|
||||
+ File.separator + "textures"
|
||||
+ File.separator + "font"
|
||||
+ File.separator + (custom ? file : codePoints + ".png")
|
||||
);
|
||||
try {
|
||||
FileUtils.copyFile(pngFile, destination);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(new File(plugin.getDataDirectory().toFile(), "tmp" + File.separator + codePoints + ".json")))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
@@ -883,6 +903,7 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
|
||||
// free resources
|
||||
MemoryUtil.memFree(byteBuffer);
|
||||
FreeTypeUtils.release();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -930,7 +951,7 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
.advance(dataMap)
|
||||
.fontProviderFunction(function)
|
||||
.build();
|
||||
charFontWidthDataMap.put(id, fontWidthData);
|
||||
this.charFontWidthDataMap.put(id, fontWidthData);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1018,6 +1039,7 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.textWidthCache.invalidateAll();
|
||||
this.configFontWidthDataMap.clear();
|
||||
}
|
||||
|
||||
@@ -1025,7 +1047,6 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
public void disable() {
|
||||
this.unload();
|
||||
this.charFontWidthDataMap.clear();
|
||||
FreeTypeUtils.release();
|
||||
}
|
||||
|
||||
private void loadTemplates() {
|
||||
@@ -1215,15 +1236,17 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
return totalAdvance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Override
|
||||
public List<Tuple<String, Key, Boolean>> miniMessageToIterable(String text) {
|
||||
if (AdventureHelper.legacySupport) text = AdventureHelper.legacyToMiniMessage(text);
|
||||
ElementNode node = (ElementNode) AdventureHelper.miniMessage().deserializeToTree(text);
|
||||
ArrayList<Tuple<String, Key, Boolean>> iterableTexts = new ArrayList<>();
|
||||
List<Tuple<String, Key, Boolean>> iterableTexts = new ObjectArrayList<>();
|
||||
nodeToIterableTexts(node, iterableTexts, MINECRAFT_DEFAULT_FONT, false);
|
||||
return iterableTexts;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
private void nodeToIterableTexts(ElementNode node, List<Tuple<String, Key, Boolean>> list, Key font, boolean bold) {
|
||||
if (node instanceof ValueNode valueNode) {
|
||||
String text = valueNode.value();
|
||||
|
||||
+8
-2
@@ -18,6 +18,8 @@
|
||||
package net.momirealms.customnameplates.backend.feature.background;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
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.background.Background;
|
||||
@@ -26,7 +28,10 @@ import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BackgroundManagerImpl implements BackgroundManager {
|
||||
|
||||
@@ -44,6 +49,7 @@ public class BackgroundManagerImpl implements BackgroundManager {
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (!ConfigManager.backgroundModule()) return;
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
@@ -55,7 +61,7 @@ public class BackgroundManagerImpl implements BackgroundManager {
|
||||
|
||||
@Override
|
||||
public Collection<Background> getBackgrounds() {
|
||||
return new HashSet<>(backgrounds.values());
|
||||
return new ObjectArrayList<>(backgrounds.values());
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
|
||||
+7
-2
@@ -84,14 +84,19 @@ public class BossBarManagerImpl implements BossBarManager, JoinQuitListener {
|
||||
@Override
|
||||
public void onPlayerJoin(CNPlayer player) {
|
||||
if (!ConfigManager.bossbarModule()) return;
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
Runnable r = () -> {
|
||||
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);
|
||||
};
|
||||
if (ConfigManager.delaySend() < 0) {
|
||||
r.run();
|
||||
} else {
|
||||
plugin.getScheduler().asyncLater(r, ConfigManager.delaySend() * 50L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+15
-11
@@ -17,6 +17,7 @@
|
||||
|
||||
package net.momirealms.customnameplates.backend.feature.bossbar;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
@@ -28,7 +29,6 @@ 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;
|
||||
|
||||
@@ -98,7 +98,7 @@ public class BossBarSender implements Feature, BossBar {
|
||||
timeLeft = 0;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
public synchronized void tick() {
|
||||
if (timeLeft > 0)
|
||||
timeLeft--;
|
||||
|
||||
@@ -126,7 +126,7 @@ public class BossBarSender implements Feature, BossBar {
|
||||
currentBossBar = carouselText.preParsedDynamicText().fastCreate(owner);
|
||||
|
||||
if (carouselText.updateOnDisplay()) {
|
||||
owner.forceUpdate(currentBossBar.placeholders(), Collections.emptySet());
|
||||
owner.forceUpdatePlaceholders(currentBossBar.placeholders(), Collections.emptySet());
|
||||
}
|
||||
|
||||
refresh();
|
||||
@@ -143,12 +143,12 @@ public class BossBarSender implements Feature, BossBar {
|
||||
}
|
||||
|
||||
public void show() {
|
||||
isShown = true;
|
||||
if (latestContent == null) {
|
||||
refresh();
|
||||
if (this.latestContent == null) {
|
||||
this.refresh();
|
||||
}
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().createBossBarPacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(latestContent), progress(), overlay(), color());
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().createBossBarPacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(this.latestContent), progress(), overlay(), color());
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
isShown = true;
|
||||
}
|
||||
|
||||
public boolean isShown() {
|
||||
@@ -163,7 +163,7 @@ public class BossBarSender implements Feature, BossBar {
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> allPlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
Set<Placeholder> placeholders = new ObjectOpenHashSet<>();
|
||||
for (CarouselText text : config.carouselTexts()) {
|
||||
placeholders.addAll(text.preParsedDynamicText().placeholders());
|
||||
}
|
||||
@@ -172,18 +172,22 @@ public class BossBarSender implements Feature, BossBar {
|
||||
|
||||
@Override
|
||||
public void notifyPlaceholderUpdates(CNPlayer p1, boolean force) {
|
||||
refresh();
|
||||
if (isShown()) {
|
||||
refresh();
|
||||
sendLatestBossBarName();
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
latestContent = this.currentBossBar.render(owner);
|
||||
if (this.currentBossBar == null) {
|
||||
this.latestContent = "";
|
||||
return;
|
||||
}
|
||||
this.latestContent = this.currentBossBar.render(owner);
|
||||
}
|
||||
|
||||
public void sendLatestBossBarName() {
|
||||
if (latestContent != null) {
|
||||
if (this.latestContent != null && isShown()) {
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().updateBossBarNamePacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(latestContent));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet);
|
||||
}
|
||||
|
||||
+57
-11
@@ -19,11 +19,22 @@ package net.momirealms.customnameplates.backend.feature.bubble;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
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 it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
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.OffsetFont;
|
||||
import net.momirealms.customnameplates.api.feature.bubble.Bubble;
|
||||
import net.momirealms.customnameplates.api.feature.bubble.BubbleConfig;
|
||||
import net.momirealms.customnameplates.api.feature.bubble.BubbleManager;
|
||||
@@ -35,13 +46,14 @@ import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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 final Map<String, Bubble> bubbles = new Object2ObjectOpenHashMap<>();
|
||||
private Requirement[] sendBubbleRequirements;
|
||||
private Requirement[] viewBubbleRequirements;
|
||||
private String defaultBubbleId;
|
||||
@@ -52,7 +64,7 @@ public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
private float viewRange;
|
||||
private Set<String> blacklistChannels;
|
||||
private ChannelMode channelMode;
|
||||
private final HashMap<String, BubbleConfig> bubbleConfigs = new HashMap<>();
|
||||
private final Map<String, BubbleConfig> bubbleConfigs = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
public BubbleManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -84,12 +96,12 @@ public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
|
||||
@Override
|
||||
public Collection<Bubble> bubbles() {
|
||||
return new HashSet<>(bubbles.values());
|
||||
return new ObjectArrayList<>(bubbles.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BubbleConfig> bubbleConfigs() {
|
||||
return new HashSet<>(bubbleConfigs.values());
|
||||
return new ObjectArrayList<>(bubbleConfigs.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,8 +174,38 @@ public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
}
|
||||
|
||||
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"));
|
||||
YamlDocument document = plugin.getConfigManager().loadConfig("configs" + File.separator + "bubble.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(ConfigManager.configVersion(), "sender-requirements", '.')
|
||||
.addIgnoredRoute(ConfigManager.configVersion(), "viewer-requirements", '.')
|
||||
.addIgnoredRoute(ConfigManager.configVersion(), "bubble-settings", '.')
|
||||
.build());
|
||||
try {
|
||||
document.save(plugin.getConfigManager().resolveConfig("configs" + File.separator + "bubble.yml").toFile());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
sendBubbleRequirements = plugin.getRequirementManager().parseRequirements(document.getSection("sender-requirements"));
|
||||
viewBubbleRequirements = plugin.getRequirementManager().parseRequirements(document.getSection("viewer-requirements"));
|
||||
defaultBubbleId = document.getString("default-bubble", "chat");
|
||||
@@ -191,7 +233,7 @@ public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
.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", ""))
|
||||
.textPrefix(inner.getString("text-prefix", "").replace("{namespace}", ConfigManager.namespace()))
|
||||
.textSuffix(inner.getString("text-suffix", ""))
|
||||
.scale(ConfigUtils.vector3(inner.getString("scale", "1,1,1")))
|
||||
.build());
|
||||
@@ -265,6 +307,10 @@ public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
String fullText = config.textPrefix() + AdventureHelper.stripTags(message.replace("\\", "\\\\")) + config.textSuffix();
|
||||
int lines = plugin.getAdvanceManager().getLines(fullText, config.lineWidth());
|
||||
if (lines > config.maxLines()) return;
|
||||
if (lines <= 0) return;
|
||||
int space = (int) plugin.getAdvanceManager().getLineAdvance(" ");
|
||||
String fakeSpace = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(space));
|
||||
fullText = fullText.replace(" ", fakeSpace);
|
||||
|
||||
TagRenderer renderer = plugin.getUnlimitedTagManager().getTagRender(player);
|
||||
if (renderer == null) return;
|
||||
@@ -282,14 +328,14 @@ public class BubbleManagerImpl implements BubbleManager, ChatListener {
|
||||
advance = config.lineWidth();
|
||||
}
|
||||
|
||||
BubbleTag bubbleTagText = new BubbleTag(player, renderer, channel, config,
|
||||
BubbleTag bubbleTag = 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);
|
||||
renderer.addTag(bubbleTag);
|
||||
if (delay != 0) {
|
||||
plugin.getScheduler().asyncLater(() -> bubbleTagText.setCanShow(true), delay * 50L, TimeUnit.MILLISECONDS);
|
||||
plugin.getScheduler().asyncLater(() -> bubbleTag.setCanShow(true), delay * 50L, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
bubbleTagText.setCanShow(true);
|
||||
bubbleTag.setCanShow(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-15
@@ -103,6 +103,10 @@ public class BubbleTag extends AbstractTag {
|
||||
return canShow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void darkTag(CNPlayer viewer, boolean dark) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShow(CNPlayer viewer) {
|
||||
if (!viewer.isMet(owner, manager.viewBubbleRequirements())) {
|
||||
@@ -180,20 +184,18 @@ public class BubbleTag extends AbstractTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTranslation() {
|
||||
for (CNPlayer player : viewerArray) {
|
||||
Tracker tracker = owner.getTracker(player);
|
||||
if (tracker != null) {
|
||||
Vector3 translation = translation(player);
|
||||
Consumer<List<Object>> modifier1 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation.multiply(tracker.getScale()).add(0.01,0,0.01));
|
||||
Object packet1 = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier1));
|
||||
if (background != null) {
|
||||
Consumer<List<Object>> modifier2 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation.multiply(tracker.getScale()));
|
||||
Object packet2 = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(subEntityID, List.of(modifier2));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(player, List.of(packet1, packet2));
|
||||
} else {
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(player, packet1);
|
||||
}
|
||||
public void updateTranslation(CNPlayer viewer) {
|
||||
Tracker tracker = owner.getTracker(viewer);
|
||||
if (tracker != null) {
|
||||
Vector3 translation = translation(viewer);
|
||||
Consumer<List<Object>> modifier1 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation.multiply(tracker.getScale()).add(0.01,0,0.01));
|
||||
Object packet1 = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier1));
|
||||
if (background != null) {
|
||||
Consumer<List<Object>> modifier2 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation.multiply(tracker.getScale()));
|
||||
Object packet2 = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(subEntityID, List.of(modifier2));
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, List.of(packet1, packet2));
|
||||
} else {
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,7 +231,8 @@ public class BubbleTag extends AbstractTag {
|
||||
@Override
|
||||
public void hide(CNPlayer viewer) {
|
||||
if (!isShown()) return;
|
||||
viewers.remove(viewer);
|
||||
boolean removed = viewers.remove(viewer);
|
||||
if (!removed) return;
|
||||
resetViewerArray();
|
||||
if (background != null) {
|
||||
owner.untrackPassengers(viewer, entityID, subEntityID);
|
||||
@@ -275,6 +278,11 @@ public class BubbleTag extends AbstractTag {
|
||||
return new Vector3(0, manager.verticalOffset() + maxY(viewer), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean relativeTranslation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public double maxY(CNPlayer viewer) {
|
||||
double y = 0;
|
||||
for (Tag tag : renderer.tags()) {
|
||||
@@ -302,4 +310,9 @@ public class BubbleTag extends AbstractTag {
|
||||
public boolean affectedByScaling() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedBySpectator() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+1
@@ -110,6 +110,7 @@ public abstract class AbstractChatManager implements ChatManager {
|
||||
@Override
|
||||
public void onChat(CNPlayer player, String message, String channel) {
|
||||
String text = message;
|
||||
plugin.debug(() -> player.name() + " says [" + message + "]");
|
||||
for (EmojiProvider provider : emojiProviders) {
|
||||
text = provider.replace(player, text);
|
||||
}
|
||||
|
||||
+10
-4
@@ -18,8 +18,11 @@
|
||||
package net.momirealms.customnameplates.backend.feature.image;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
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.image.Animation;
|
||||
import net.momirealms.customnameplates.api.feature.image.Image;
|
||||
import net.momirealms.customnameplates.api.feature.image.ImageManager;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
@@ -28,7 +31,6 @@ 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 {
|
||||
@@ -47,6 +49,7 @@ public class ImageManagerImpl implements ImageManager {
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (!ConfigManager.imageModule()) return;
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
@@ -57,7 +60,7 @@ public class ImageManagerImpl implements ImageManager {
|
||||
|
||||
@Override
|
||||
public Collection<Image> images() {
|
||||
return new HashSet<>(images.values());
|
||||
return new ObjectArrayList<>(images.values());
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
@@ -71,8 +74,11 @@ public class ImageManagerImpl implements ImageManager {
|
||||
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))
|
||||
.animation(config.contains("animation") ? new Animation(
|
||||
config.getInt("animation.speed", 64),
|
||||
config.getInt("animation.frames", 1)
|
||||
) : null)
|
||||
.removeShadow(!config.getBoolean("shadow", true))
|
||||
.character(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("image") + ".png"),
|
||||
config.getInt("ascent", 8),
|
||||
|
||||
+6
-2
@@ -18,7 +18,9 @@
|
||||
package net.momirealms.customnameplates.backend.feature.nameplate;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
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.nameplate.Nameplate;
|
||||
@@ -48,6 +50,7 @@ public class NameplateManagerImpl implements NameplateManager {
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadConfig();
|
||||
if (!ConfigManager.nameplateModule()) return;
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
@@ -59,7 +62,7 @@ public class NameplateManagerImpl implements NameplateManager {
|
||||
|
||||
@Override
|
||||
public Collection<Nameplate> nameplates() {
|
||||
return new HashSet<>(nameplates.values());
|
||||
return new ObjectArrayList<>(nameplates.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,6 +116,7 @@ public class NameplateManagerImpl implements NameplateManager {
|
||||
Nameplate nameplate = Nameplate.builder()
|
||||
.id(id)
|
||||
.displayName(config.getString("display-name", id))
|
||||
.minWidth(config.getInt("min-width", 0))
|
||||
.left(ConfiguredCharacter.create(
|
||||
ConfigUtils.getFileInTheSameFolder(configFile, config.getString("left.image") + ".png"),
|
||||
config.getInt("left.ascent", 12),
|
||||
@@ -134,7 +138,7 @@ public class NameplateManagerImpl implements NameplateManager {
|
||||
}
|
||||
|
||||
private void saveDefaultNameplates() {
|
||||
String[] png_list = new String[]{"cat", "egg", "cheems", "wither", "xmas", "halloween", "hutao", "starsky", "trident", "rabbit"};
|
||||
String[] png_list = new String[]{"egg", "xmas", "halloween", "hutao", "starsky", "trident", "rabbit", "sign", "game", "enter", "panda", "angel", "banner"};
|
||||
String[] part_list = new String[]{"_left.png", "_middle.png", "_right.png", ".yml"};
|
||||
for (String name : png_list) {
|
||||
for (String part : part_list) {
|
||||
|
||||
+102
-24
@@ -29,6 +29,7 @@ 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.Animation;
|
||||
import net.momirealms.customnameplates.api.feature.image.Image;
|
||||
import net.momirealms.customnameplates.api.feature.nameplate.Nameplate;
|
||||
import net.momirealms.customnameplates.api.feature.pack.ResourcePackManager;
|
||||
@@ -40,6 +41,7 @@ import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
@@ -69,19 +71,34 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
// 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);
|
||||
if (ConfigManager.enableShader()) {
|
||||
if (VersionHelper.isVersionNewerThan1_21_2()) {
|
||||
this.generateShaders("ResourcePack" + File.separator + "overlay_1_21_2" + 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_21_2"),
|
||||
new File(plugin.getDataFolder(), "ResourcePack")
|
||||
);
|
||||
FileUtils.deleteDirectory(new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_21_2"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else if (VersionHelper.isVersionNewerThan1_20_5()) {
|
||||
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);
|
||||
}
|
||||
this.generateShaders("ResourcePack" + File.separator + "overlay_1_21_2" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true);
|
||||
} else {
|
||||
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);
|
||||
this.generateShaders("ResourcePack" + File.separator + "overlay_1_21_2" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +189,11 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private void setPackFormat() {
|
||||
if (VersionHelper.isVersionNewerThan1_20_5()) {
|
||||
if (VersionHelper.isVersionNewerThan1_21_2()) {
|
||||
plugin.getConfigManager().saveResource("ResourcePack" + File.separator + "pack_1_21_2.mcmeta");
|
||||
File file = new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "pack_1_21_2.mcmeta");
|
||||
file.renameTo(new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "pack.mcmeta"));
|
||||
} else 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"));
|
||||
@@ -216,6 +237,21 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
plugin.getPluginLogger().warn("Failed to copy files to Oraxen", e);
|
||||
}
|
||||
}
|
||||
if (ConfigManager.packNexo()){
|
||||
try {
|
||||
FileUtils.deleteDirectory(new File(pluginsFolder, "Nexo" + File.separator + "pack" + File.separator + "external_packs" + File.separator + "CustomNameplates"));
|
||||
FileUtils.copyDirectory(resourcePackFolder, new File(pluginsFolder, "Nexo" + File.separator + "pack" + File.separator + "external_packs" + File.separator + "CustomNameplates"));
|
||||
} catch (IOException e){
|
||||
plugin.getPluginLogger().warn("Failed to copy files to Nexo", e);
|
||||
}
|
||||
}
|
||||
if(ConfigManager.packCreativeCentral()) {
|
||||
try {
|
||||
FileUtils.copyDirectory(new File(resourcePackFolder, "assets"), new File(pluginsFolder, "creative-central" + File.separator + "resources" + File.separator + "assets"));
|
||||
} catch (IOException e){
|
||||
plugin.getPluginLogger().warn("Failed to copy files to Creative-Central", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<JsonObject> getBubbles(File texturesFolder) {
|
||||
@@ -295,11 +331,53 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
jo.add("chars", ja);
|
||||
list.add(jo);
|
||||
try {
|
||||
File targetFile = new File(texturesFolder,
|
||||
ConfigManager.imagePath().replace("\\", File.separator) + character.imageFile().getName());
|
||||
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()));
|
||||
"contents" + File.separator + "images" + File.separator + character.imageFile().getName()), targetFile);
|
||||
if (image.removeShadow() || image.animation() != null) {
|
||||
BufferedImage bufferedImage = ImageIO.read(targetFile);
|
||||
if (image.removeShadow()) {
|
||||
for (int y = 0; y < bufferedImage.getHeight(); y++) {
|
||||
for (int x = 0; x < bufferedImage.getWidth(); x++) {
|
||||
int argb = bufferedImage.getRGB(x, y);
|
||||
int alpha = (argb >> 24) & 0xff;
|
||||
if (alpha != 0) {
|
||||
int rgb = argb & 0x00ffffff;
|
||||
int newArgb = (254 << 24) | rgb;
|
||||
bufferedImage.setRGB(x, y, newArgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Animation animation = image.animation();
|
||||
if (animation != null) {
|
||||
int height = bufferedImage.getHeight();
|
||||
int extra = height % animation.frames();
|
||||
if (extra > 0) {
|
||||
plugin.getPluginLogger().warn("Image height is not a multiple of frame rate: " + image.id());
|
||||
continue;
|
||||
}
|
||||
int eachFrameHeight = height / animation.frames();
|
||||
int width = bufferedImage.getWidth();
|
||||
int speed = Math.min(Math.max(animation.speed(), 1), 255);
|
||||
|
||||
int alpha = 1;
|
||||
int red = speed;
|
||||
int green = width;
|
||||
int blue = eachFrameHeight;
|
||||
int argb = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||
|
||||
for (int i = 0; i < animation.frames(); i++) {
|
||||
int y = i * eachFrameHeight;
|
||||
bufferedImage.setRGB(0, y, argb);
|
||||
}
|
||||
}
|
||||
|
||||
ImageIO.write(bufferedImage, "png", targetFile);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -418,14 +496,14 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
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";
|
||||
var destination = "ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "textures" + File.separator + "font";
|
||||
File imageFile = new File(plugin.getDataFolder(), path);
|
||||
File destinationFile = new File(plugin.getDataFolder(), destination);
|
||||
File destinationFolder = new File(plugin.getDataFolder(), destination);
|
||||
if (imageFile.exists()) {
|
||||
try {
|
||||
FileUtils.copyFile(imageFile, destinationFile);
|
||||
FileUtils.copyFileToDirectory(imageFile, destinationFolder);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,7 +511,6 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -486,7 +563,7 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
public static class ShaderConstants {
|
||||
|
||||
public static final String Nameplates_Shader_1_20_5 =
|
||||
"if (Color.xyz == vec3(255., 254., 253.) / 255.) {\n" +
|
||||
"if (Color.xyz == vec3(255., 254., 253.) / 255. && (Position.z == 50.03 || Position.z == 200.03 || Position.z == 400.03 || Position.z == 1000.03 || Position.z == 2000 || Position.z == 2200.03 || Position.z == 2400.06 || Position.z == 2400.12 || Position.z == 2650.03 || Position.z == 2800.03)) {\n" +
|
||||
" vertexColor = Color * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.y += 1;\n" +
|
||||
" vertex.x += 1;\n" +
|
||||
@@ -505,7 +582,7 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
" }";
|
||||
|
||||
public static final String Nameplates_Shader_1_20_4 =
|
||||
"if (Color.xyz == vec3(255., 254., 253.) / 255.) {\n" +
|
||||
"if (Color.xyz == vec3(255., 254., 253.) / 255. && (Position.z == 0.03 || Position.z == 0.06 || Position.z == 0.12 || Position.z == 100.03 || Position.z == 200.03 || Position.z == 400.03)) {\n" +
|
||||
" vertexColor = Color * texelFetch(Sampler2, UV2 / 16, 0);\n" +
|
||||
" vertex.y += 1;\n" +
|
||||
" vertex.x += 1;\n" +
|
||||
@@ -558,6 +635,7 @@ public class ResourcePackManagerImpl implements ResourcePackManager {
|
||||
" 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" +
|
||||
|
||||
+26
-11
@@ -17,6 +17,7 @@
|
||||
|
||||
package net.momirealms.customnameplates.backend.feature.tag;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.CarouselText;
|
||||
@@ -31,7 +32,6 @@ 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;
|
||||
|
||||
@@ -63,7 +63,9 @@ public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
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(),
|
||||
component, config.backgroundColor(),
|
||||
(owner.isSpectator() && affectedBySpectator()) || (owner.isCrouching() && affectedByCrouching()) ? 64 : 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)),
|
||||
@@ -101,7 +103,7 @@ public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
currentText = carouselText.preParsedDynamicText().fastCreate(owner);
|
||||
|
||||
if (carouselText.updateOnDisplay()) {
|
||||
owner.forceUpdate(currentText.placeholders(), owner.nearbyPlayers());
|
||||
owner.forceUpdatePlaceholders(currentText.placeholders(), owner.nearbyPlayers());
|
||||
}
|
||||
|
||||
refresh();
|
||||
@@ -129,22 +131,25 @@ public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
if (!isShown()) return;
|
||||
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);
|
||||
if (isShown(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);
|
||||
Tracker tracker = owner.getTracker(viewer);
|
||||
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;
|
||||
}
|
||||
@@ -172,6 +177,11 @@ public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
return config.translation().add(0, renderer.hatOffset(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean relativeTranslation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "UnlimitedTag";
|
||||
@@ -185,7 +195,7 @@ public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
|
||||
@Override
|
||||
public Set<Placeholder> allPlaceholders() {
|
||||
HashSet<Placeholder> placeholders = new HashSet<>();
|
||||
Set<Placeholder> placeholders = new ObjectOpenHashSet<>();
|
||||
for (CarouselText text : config.carouselTexts()) {
|
||||
placeholders.addAll(text.preParsedDynamicText().placeholders());
|
||||
}
|
||||
@@ -204,11 +214,16 @@ public class NameTag extends AbstractTag implements RelationalFeature {
|
||||
|
||||
@Override
|
||||
public boolean affectedByCrouching() {
|
||||
return config.affectedByScaling();
|
||||
return config.affectedByCrouching();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByScaling() {
|
||||
return affectedByCrouching();
|
||||
return config.affectedByScaling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedBySpectator() {
|
||||
return config.affectedBySpectator();
|
||||
}
|
||||
}
|
||||
+157
-94
@@ -17,6 +17,7 @@
|
||||
|
||||
package net.momirealms.customnameplates.backend.feature.tag;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.Feature;
|
||||
@@ -24,31 +25,34 @@ import net.momirealms.customnameplates.api.feature.tag.NameTagConfig;
|
||||
import net.momirealms.customnameplates.api.feature.tag.Tag;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TagRenderer;
|
||||
import net.momirealms.customnameplates.api.feature.tag.UnlimitedTagManager;
|
||||
import net.momirealms.customnameplates.api.helper.VersionHelper;
|
||||
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.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class TagRendererImpl implements TagRenderer {
|
||||
|
||||
private final CNPlayer owner;
|
||||
private final UnlimitedTagManager manager;
|
||||
private Tag[] tags;
|
||||
private final Vector<Tag> tagVector;
|
||||
private Tag[] tagArray;
|
||||
private Tag[] rTagsArray;
|
||||
private double hatOffset;
|
||||
private boolean valid = true;
|
||||
|
||||
public TagRendererImpl(UnlimitedTagManager manager, CNPlayer owner) {
|
||||
this.owner = owner;
|
||||
this.manager = manager;
|
||||
List<NameTag> senderList = new ArrayList<>();
|
||||
List<NameTag> tagList = new ArrayList<>();
|
||||
for (NameTagConfig config : manager.nameTagConfigs()) {
|
||||
NameTag sender = new NameTag(owner, config, this);
|
||||
senderList.add(sender);
|
||||
tagList.add(sender);
|
||||
this.owner.addFeature(sender);
|
||||
}
|
||||
this.tags = senderList.toArray(new Tag[0]);
|
||||
this.tagVector = new Vector<>(tagList);
|
||||
this.resetTagArray();
|
||||
this.rTagsArray = new Tag[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,57 +64,64 @@ public class TagRendererImpl implements TagRenderer {
|
||||
public void hatOffset(double hatOffset) {
|
||||
if (hatOffset != this.hatOffset) {
|
||||
this.hatOffset = hatOffset;
|
||||
for (Tag tag : tags) {
|
||||
for (Tag tag : tagArray) {
|
||||
tag.updateTranslation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
HashSet<CNPlayer> playersToUpdatePassengers = new HashSet<>();
|
||||
for (Tag display : tags) {
|
||||
boolean canShow = display.canShow();
|
||||
// 能大众显示
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onTick() {
|
||||
if (!isValid()) return;
|
||||
|
||||
Set<CNPlayer> playersToUpdatePassengers = new ObjectOpenHashSet<>();
|
||||
Set<CNPlayer> tagTranslationUpdates = new ObjectOpenHashSet<>();
|
||||
|
||||
Collection<CNPlayer> nearbyPlayers = owner.nearbyPlayers();
|
||||
for (Tag tag : tagArray) {
|
||||
boolean canShow = tag.canShow();
|
||||
if (canShow) {
|
||||
// 当前大众显示
|
||||
if (display.isShown()) {
|
||||
for (CNPlayer nearby : owner.nearbyPlayers()) {
|
||||
// 如果已经展示了
|
||||
if (display.isShown(nearby)) {
|
||||
// 不满足条件就撤掉
|
||||
if (!display.canShow(nearby)) {
|
||||
display.hide(nearby);
|
||||
if (tag.isShown()) {
|
||||
for (CNPlayer nearby : nearbyPlayers) {
|
||||
if (tag.isShown(nearby)) {
|
||||
if (!tag.canShow(nearby)) {
|
||||
tag.hide(nearby);
|
||||
if (!tag.relativeTranslation())
|
||||
tagTranslationUpdates.add(nearby);
|
||||
}
|
||||
} else {
|
||||
// 未展示,则检测条件,可以就上
|
||||
if (display.canShow(nearby)) {
|
||||
display.show(nearby);
|
||||
if (tag.canShow(nearby)) {
|
||||
tag.show(nearby);
|
||||
playersToUpdatePassengers.add(nearby);
|
||||
if (!tag.relativeTranslation())
|
||||
tagTranslationUpdates.add(nearby);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新一下文字顺序,放在后面是为了防止已经被hide的玩家多收一个包
|
||||
display.tick();
|
||||
tag.tick();
|
||||
} else {
|
||||
// 之前隐藏,现在开始大众显示
|
||||
// 需要重置文字顺序
|
||||
display.init();
|
||||
// 更新一下文字顺序
|
||||
display.tick();
|
||||
display.show();
|
||||
for (CNPlayer nearby : owner.nearbyPlayers()) {
|
||||
if (display.canShow(nearby) && !display.isShown(nearby)) {
|
||||
display.show(nearby);
|
||||
tag.init();
|
||||
tag.tick();
|
||||
tag.show();
|
||||
for (CNPlayer nearby : nearbyPlayers) {
|
||||
if (tag.canShow(nearby) && !tag.isShown(nearby)) {
|
||||
tag.show(nearby);
|
||||
playersToUpdatePassengers.add(nearby);
|
||||
if (!tag.relativeTranslation())
|
||||
tagTranslationUpdates.add(nearby);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 不能展示的情况
|
||||
// 如果已经展示了,就咔掉所有玩家
|
||||
if (display.isShown()) {
|
||||
display.hide();
|
||||
if (tag.isShown()) {
|
||||
tag.hide();
|
||||
if (!tag.relativeTranslation())
|
||||
tagTranslationUpdates.addAll(nearbyPlayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,11 +131,21 @@ public class TagRendererImpl implements TagRenderer {
|
||||
for (CNPlayer nearby : playersToUpdatePassengers) {
|
||||
updatePassengers(nearby, realPassengers);
|
||||
}
|
||||
|
||||
// Update relative translation tags
|
||||
for (Tag tag : rTagsArray) {
|
||||
for (CNPlayer nearby : tagTranslationUpdates) {
|
||||
if (tag.isShown(nearby)) {
|
||||
tag.updateTranslation(nearby);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
for (Tag tag : this.tags) {
|
||||
this.valid = false;
|
||||
for (Tag tag : this.tagArray) {
|
||||
tag.hide();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.removeFeature(feature);
|
||||
@@ -133,7 +154,7 @@ public class TagRendererImpl implements TagRenderer {
|
||||
}
|
||||
|
||||
public void handlePlayerRemove(CNPlayer another) {
|
||||
for (Tag display : this.tags) {
|
||||
for (Tag display : this.tagArray) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
display.hide(another);
|
||||
@@ -142,79 +163,99 @@ public class TagRendererImpl implements TagRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void resetRTagArray() {
|
||||
List<Tag> rTags = new ArrayList<>();
|
||||
for (Tag tag : this.tagArray) {
|
||||
if (tag.relativeTranslation()) rTags.add(tag);
|
||||
}
|
||||
this.rTagsArray = rTags.toArray(new Tag[0]);
|
||||
}
|
||||
|
||||
private void resetTagArray() {
|
||||
this.tagArray = tagVector.toArray(new Tag[0]);
|
||||
}
|
||||
|
||||
@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 (tagVector.contains(tag)) {
|
||||
return;
|
||||
}
|
||||
tagVector.add(tag);
|
||||
resetTagArray();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.addFeature(feature);
|
||||
}
|
||||
if (tag.relativeTranslation()) {
|
||||
resetRTagArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTag(Tag tag, int index) {
|
||||
if (index < 0 || index > this.tagArray.length) {
|
||||
throw new IndexOutOfBoundsException("Index out of bounds: " + index);
|
||||
}
|
||||
tagVector.add(index, tag);
|
||||
resetTagArray();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.addFeature(feature);
|
||||
}
|
||||
if (tag.relativeTranslation()) {
|
||||
resetRTagArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag[] tags() {
|
||||
return this.tags;
|
||||
return this.tagArray;
|
||||
}
|
||||
|
||||
@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])) {
|
||||
List<Integer> removedIndexes = new ArrayList<>();
|
||||
boolean hasRTag = false;
|
||||
for (int i = 0; i < this.tagArray.length; i++) {
|
||||
Tag tag = this.tagArray[i];
|
||||
if (predicate.test(tag)) {
|
||||
removedIndexes.add(i);
|
||||
this.tags[i].hide();
|
||||
if (this.tags[i] instanceof Feature feature) {
|
||||
tag.hide();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.removeFeature(feature);
|
||||
}
|
||||
if (tag.relativeTranslation()) {
|
||||
hasRTag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
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];
|
||||
}
|
||||
Collections.reverse(removedIndexes);
|
||||
for (int index : removedIndexes) {
|
||||
this.tagVector.remove(index);
|
||||
}
|
||||
resetTagArray();
|
||||
if (hasRTag) {
|
||||
resetRTagArray();
|
||||
}
|
||||
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)) {
|
||||
for (int i = 0; i < this.tagArray.length; i++) {
|
||||
if (this.tagArray[i] == 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) {
|
||||
for (Tag display : this.tagArray) {
|
||||
if (display == tag) {
|
||||
has = true;
|
||||
break;
|
||||
@@ -222,20 +263,21 @@ public class TagRendererImpl implements TagRenderer {
|
||||
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;
|
||||
this.tagVector.remove(tag);
|
||||
resetTagArray();
|
||||
tag.hide();
|
||||
if (tag instanceof Feature feature) {
|
||||
this.owner.removeFeature(feature);
|
||||
}
|
||||
if (tag.relativeTranslation()) {
|
||||
resetRTagArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePlayerAdd(CNPlayer another) {
|
||||
boolean updatePassengers = false;
|
||||
for (Tag display : this.tags) {
|
||||
for (Tag display : this.tagArray) {
|
||||
if (display.isShown()) {
|
||||
if (!display.isShown(another)) {
|
||||
if (display.canShow(another)) {
|
||||
@@ -260,19 +302,41 @@ public class TagRendererImpl implements TagRenderer {
|
||||
passengers[index++] = passenger;
|
||||
}
|
||||
Object packet = CustomNameplates.getInstance().getPlatform().setPassengersPacket(owner.entityID(), passengers);
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet);
|
||||
if (VersionHelper.isPaperOrItsForks()) {
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet);
|
||||
} else {
|
||||
CustomNameplates.getInstance().getScheduler().sync().runLater(() -> {
|
||||
CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet);
|
||||
}, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleEntityDataChange(CNPlayer another, boolean isCrouching) {
|
||||
Tracker properties = owner.getTracker(another);
|
||||
Tracker tracker = owner.getTracker(another);
|
||||
// should never be null
|
||||
if (properties == null) return;
|
||||
properties.setCrouching(isCrouching);
|
||||
for (Tag display : this.tags) {
|
||||
if (tracker == null) return;
|
||||
tracker.setCrouching(isCrouching);
|
||||
for (Tag display : this.tagArray) {
|
||||
if (display.affectedByCrouching()) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
display.onPlayerCrouching(another, isCrouching);
|
||||
display.darkTag(another, isCrouching || (display.affectedBySpectator() && tracker.isSpectator()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleGameModeChange(CNPlayer another, boolean isSpectator) {
|
||||
Tracker tracker = owner.getTracker(another);
|
||||
// can be null
|
||||
if (tracker == null) return;
|
||||
tracker.setSpectator(isSpectator);
|
||||
for (Tag display : this.tagArray) {
|
||||
if (display.affectedBySpectator()) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
display.darkTag(another, isSpectator || (display.affectedByCrouching() && tracker.isCrouching()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,12 +344,11 @@ public class TagRendererImpl implements TagRenderer {
|
||||
}
|
||||
|
||||
public void handleAttributeChange(CNPlayer another, double scale) {
|
||||
boolean updatePassengers = false;
|
||||
Tracker properties = owner.getTracker(another);
|
||||
Tracker tracker = owner.getTracker(another);
|
||||
// should never be null
|
||||
if (properties == null) return;
|
||||
properties.setScale(scale);
|
||||
for (Tag display : this.tags) {
|
||||
if (tracker == null) return;
|
||||
tracker.setScale(scale);
|
||||
for (Tag display : this.tagArray) {
|
||||
if (display.affectedByScaling()) {
|
||||
if (display.isShown()) {
|
||||
if (display.isShown(another)) {
|
||||
|
||||
+113
-13
@@ -19,12 +19,21 @@ package net.momirealms.customnameplates.backend.feature.tag;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
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.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.feature.PlayerListener;
|
||||
import net.momirealms.customnameplates.api.feature.tag.NameTagConfig;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TagRenderer;
|
||||
import net.momirealms.customnameplates.api.feature.tag.UnlimitedTagManager;
|
||||
@@ -36,12 +45,14 @@ import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import net.momirealms.customnameplates.api.util.Vector3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitListener {
|
||||
public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitListener, PlayerListener {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final LinkedHashMap<String, NameTagConfig> configs = new LinkedHashMap<>();
|
||||
@@ -55,23 +66,73 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreviewing(CNPlayer player, boolean preview) {
|
||||
boolean isPreviewing = player.isPreviewing();
|
||||
public void setTempPreviewing(CNPlayer player, boolean preview) {
|
||||
boolean isPreviewing = player.isTempPreviewing();
|
||||
if (isPreviewing) {
|
||||
if (preview) return;
|
||||
plugin.getUnlimitedTagManager().onRemovePlayer(player, player);
|
||||
onRemovePlayer(player, player);
|
||||
player.removePlayerFromTracker(player);
|
||||
((AbstractCNPlayer) player).setPreviewing(false);
|
||||
((AbstractCNPlayer) player).setTempPreviewing(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);
|
||||
tracker.setSpectator(player.isSpectator());
|
||||
onAddPlayer(player, player);
|
||||
((AbstractCNPlayer) player).setTempPreviewing(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void togglePreviewing(CNPlayer player, boolean preview) {
|
||||
boolean isPreviewing = player.isToggleablePreviewing();
|
||||
if (isPreviewing) {
|
||||
if (preview) return;
|
||||
onRemovePlayer(player, player);
|
||||
player.removePlayerFromTracker(player);
|
||||
((AbstractCNPlayer) player).setToggleablePreviewing(false);
|
||||
} else {
|
||||
if (!preview) return;
|
||||
Tracker tracker = player.addPlayerToTracker(player);
|
||||
tracker.setScale(player.scale());
|
||||
tracker.setCrouching(player.isCrouching());
|
||||
tracker.setSpectator(player.isSpectator());
|
||||
onAddPlayer(player, player);
|
||||
((AbstractCNPlayer) player).setToggleablePreviewing(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeWorld(CNPlayer player) {
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
if (player.isOnline() && (player.isTempPreviewing() || player.isToggleablePreviewing())) {
|
||||
onRemovePlayer(player, player);
|
||||
onAddPlayer(player, player);
|
||||
}
|
||||
}, VersionHelper.isFolia() ? 500 : 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRespawn(CNPlayer player) {
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
if (player.isOnline() && (player.isTempPreviewing() || player.isToggleablePreviewing())) {
|
||||
onRemovePlayer(player, player);
|
||||
onAddPlayer(player, player);
|
||||
}
|
||||
}, VersionHelper.isFolia() ? 500 : 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTeleport(CNPlayer player) {
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
if (player.isOnline() && (player.isTempPreviewing() || player.isToggleablePreviewing())) {
|
||||
onRemovePlayer(player, player);
|
||||
onAddPlayer(player, player);
|
||||
}
|
||||
}, VersionHelper.isFolia() ? 500 : 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previewDuration() {
|
||||
return previewDuration;
|
||||
@@ -79,13 +140,17 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis
|
||||
|
||||
@Override
|
||||
public void onPlayerJoin(CNPlayer player) {
|
||||
plugin.debug(() -> player.name() + " joined the server");
|
||||
TagRendererImpl sender = new TagRendererImpl(this, player);
|
||||
sender.onTick();
|
||||
TagRendererImpl previous = tagRenderers.put(player.uuid(), sender);
|
||||
if (previous != null) {
|
||||
previous.destroy();
|
||||
}
|
||||
setPreviewing(player, isAlwaysShow());
|
||||
if (isAlwaysShow()) {
|
||||
setTempPreviewing(player, isAlwaysShow());
|
||||
} else if (player.isLoaded() && player.isTempPreviewing()) {
|
||||
setTempPreviewing(player, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,7 +163,6 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (!ConfigManager.nameplateModule()) return;
|
||||
this.loadConfig();
|
||||
this.resetArray();
|
||||
for (CNPlayer online : plugin.getOnlinePlayers()) {
|
||||
@@ -179,13 +243,48 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerGameModeChange(CNPlayer owner, CNPlayer viewer, boolean isSpectator) {
|
||||
TagRendererImpl controller = tagRenderers.get(owner.uuid());
|
||||
if (controller != null) {
|
||||
controller.handleGameModeChange(viewer, isSpectator);
|
||||
}
|
||||
}
|
||||
|
||||
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"));
|
||||
YamlDocument document = plugin.getConfigManager().loadConfig("configs" + File.separator + "nameplate.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(ConfigManager.configVersion(), "unlimited", '.')
|
||||
.build());
|
||||
try {
|
||||
document.save(plugin.getConfigManager().resolveConfig("configs" + File.separator + "nameplate.yml").toFile());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
previewDuration = document.getInt("preview-duration", 5);
|
||||
alwaysShow = document.getBoolean("always-show", false);
|
||||
Section unlimitedSection = document.getSection("unlimited");
|
||||
if (unlimitedSection == null) return;
|
||||
if (!ConfigManager.nametagModule() || unlimitedSection == null) return;
|
||||
for (Map.Entry<String, Object> entry : unlimitedSection.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (!(entry.getValue() instanceof Section section))
|
||||
return;
|
||||
@@ -208,6 +307,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis
|
||||
.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))
|
||||
.affectedBySpectator(section.getBoolean("affected-by-spectator", true))
|
||||
.affectedByScaling(section.getBoolean("affected-by-scale-attribute", true))
|
||||
.carouselText(
|
||||
section.contains("text") ?
|
||||
|
||||
+136
-64
@@ -19,6 +19,10 @@ package net.momirealms.customnameplates.backend.placeholder;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
@@ -44,8 +48,6 @@ import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
|
||||
@@ -53,10 +55,11 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final HashMap<String, Integer> refreshIntervals = new HashMap<>();
|
||||
private final Int2IntOpenHashMap fasterRefreshIntervals = new Int2IntOpenHashMap();
|
||||
private final Map<String, Placeholder> registeredPlaceholders = new HashMap<>();
|
||||
private final HashMap<Placeholder, List<PreParsedDynamicText>> childrenText = new HashMap<>();
|
||||
private final List<PreParsedDynamicText> delayedInitTexts = new ArrayList<>();
|
||||
private final HashMap<String, Placeholder> nestedPlaceholders = new HashMap<>();
|
||||
private final List<PreParsedDynamicText> delayedInitTexts = new ArrayList<>();
|
||||
|
||||
public PlaceholderManagerImpl(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -84,7 +87,10 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
Placeholder placeholder = entry.getKey();
|
||||
for (PreParsedDynamicText preParsedText : entry.getValue()) {
|
||||
preParsedText.init();
|
||||
placeholder.addChildren(preParsedText.placeholders());
|
||||
for (Placeholder child : preParsedText.placeholders()) {
|
||||
placeholder.addChild(child);
|
||||
child.addParent(placeholder);
|
||||
}
|
||||
}
|
||||
this.nestedPlaceholders.put(placeholder.id().replace("%np_", "%nameplates_").replace("%rel_np_", "%rel_nameplates_"), placeholder);
|
||||
}
|
||||
@@ -100,13 +106,23 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
public void unload() {
|
||||
this.refreshIntervals.clear();
|
||||
this.registeredPlaceholders.clear();
|
||||
this.delayedInitTexts.clear();
|
||||
this.childrenText.clear();
|
||||
this.delayedInitTexts.clear();
|
||||
this.nestedPlaceholders.clear();
|
||||
this.fasterRefreshIntervals.clear();
|
||||
PlaceholderCounter.reset();
|
||||
}
|
||||
|
||||
private void loadNestNameplatePlaceholders() {
|
||||
if (!ConfigManager.nameplateModule()) {
|
||||
this.registerPlayerPlaceholder("%np_tag-image%", (player -> "Please remove %np_tag-image% if you have disabled nameplates module"));
|
||||
this.registerPlayerPlaceholder("%rel_np_tag-image%", (player -> "Please remove %rel_np_tag-image% if you have disabled nameplates module"));
|
||||
this.registerPlayerPlaceholder("%np_tag-text%", (player -> "Please remove %np_tag-text% if you have disabled nameplates module"));
|
||||
this.registerPlayerPlaceholder("%rel_np_tag-text%", (player -> "Please remove %rel_np_tag-text% if you have disabled nameplates module"));
|
||||
this.registerPlayerPlaceholder("%np_tag%", (player -> "Please remove %np_tag% if you have disabled nameplates module"));
|
||||
this.registerPlayerPlaceholder("%rel_np_tag%", (player -> "Please remove %rel_np_tag% if you have disabled nameplates module"));
|
||||
return;
|
||||
}
|
||||
PreParsedDynamicText nameTag = new PreParsedDynamicText(plugin.getNameplateManager().playerNameTag());
|
||||
Placeholder placeholder1 = this.registerPlayerPlaceholder("%np_tag-image%", (player -> {
|
||||
String equippedNameplate = player.equippedNameplate();
|
||||
@@ -115,7 +131,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
if (nameplate == null) return "";
|
||||
String tag = nameTag.fastCreate(player).render(player);
|
||||
float advance = plugin.getAdvanceManager().getLineAdvance(tag);
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImage(advance, 1, 0));
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImage(advance, 0, 0));
|
||||
}));
|
||||
Placeholder placeholder2 = this.registerRelationalPlaceholder("%rel_np_tag-image%", (p1, p2) -> {
|
||||
String equippedNameplate = p1.equippedNameplate();
|
||||
@@ -124,7 +140,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
if (nameplate == null) return "";
|
||||
String tag = nameTag.fastCreate(p1).render(p2);
|
||||
float advance = plugin.getAdvanceManager().getLineAdvance(tag);
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImage(advance, 1, 0));
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImage(advance, 0, 0));
|
||||
});
|
||||
Placeholder placeholder3 = this.registerPlayerPlaceholder("%np_tag-text%", (player -> nameTag.fastCreate(player).render(player)));
|
||||
Placeholder placeholder4 = this.registerRelationalPlaceholder("%rel_np_tag-text%", (p1, p2) -> nameTag.fastCreate(p1).render(p2));
|
||||
@@ -135,8 +151,8 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
String tag = nameTag.fastCreate(player).render(player);
|
||||
if (nameplate == null) return tag;
|
||||
float advance = plugin.getAdvanceManager().getLineAdvance(tag);
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImagePrefix(advance, 1, 0))
|
||||
+ tag + AdventureHelper.surroundWithNameplatesFont(nameplate.createImageSuffix(advance, 1, 0));
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImagePrefix(advance, 0, 0))
|
||||
+ tag + AdventureHelper.surroundWithNameplatesFont(nameplate.createImageSuffix(advance, 0, 0));
|
||||
}));
|
||||
Placeholder placeholder6 = this.registerRelationalPlaceholder("%rel_np_tag%", (p1, p2) -> {
|
||||
String equippedNameplate = p1.equippedNameplate();
|
||||
@@ -144,8 +160,8 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
if (nameplate == null) return p1.name();
|
||||
String tag = nameTag.fastCreate(p1).render(p2);
|
||||
float advance = plugin.getAdvanceManager().getLineAdvance(tag);
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImagePrefix(advance, 1, 0))
|
||||
+ tag + AdventureHelper.surroundWithNameplatesFont(nameplate.createImageSuffix(advance, 1, 0));
|
||||
return AdventureHelper.surroundWithNameplatesFont(nameplate.createImagePrefix(advance, 0, 0))
|
||||
+ tag + AdventureHelper.surroundWithNameplatesFont(nameplate.createImageSuffix(advance, 0, 0));
|
||||
});
|
||||
List<PreParsedDynamicText> list = List.of(nameTag);
|
||||
childrenText.put(placeholder1, list);
|
||||
@@ -161,22 +177,35 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
this.registerPlayerPlaceholder("%player_x%", (player -> String.valueOf((int) Math.floor(player.position().x()))));
|
||||
this.registerPlayerPlaceholder("%player_y%", (player -> String.valueOf((int) Math.floor(player.position().y()))));
|
||||
this.registerPlayerPlaceholder("%player_z%", (player -> String.valueOf((int) Math.floor(player.position().z()))));
|
||||
this.registerPlayerPlaceholder("%np_biome%", (player -> {
|
||||
Vector3 vector3 = player.position();
|
||||
return plugin.getPlatform().getBiome(player.world(), (int) Math.floor(vector3.x()), (int) Math.floor(vector3.y()), (int) Math.floor(vector3.z()));
|
||||
}));
|
||||
this.registerRelationalPlaceholder("%rel_np_biome%", (p1,p2) -> {
|
||||
Vector3 vector3 = p1.position();
|
||||
return plugin.getPlatform().getBiome(p1.world(), (int) Math.floor(vector3.x()), (int) Math.floor(vector3.y()), (int) Math.floor(vector3.z()));
|
||||
});
|
||||
this.registerPlayerPlaceholder("%player_world%", (CNPlayer::world));
|
||||
this.registerPlayerPlaceholder("%player_remaining_air%", (player -> String.valueOf(player.remainingAir())));
|
||||
for (int i = -256; i <= 256; i++) {
|
||||
String characters = OffsetFont.createOffsets(i);
|
||||
this.registerPlayerPlaceholder("%np_offset_" + i + "%", (p) -> AdventureHelper.surroundWithNameplatesFont(characters));
|
||||
}
|
||||
this.registerPlayerPlaceholder("%np_equipped_nameplate%", CNPlayer::equippedNameplate);
|
||||
this.registerPlayerPlaceholder("%np_equipped_bubble%", CNPlayer::equippedBubble);
|
||||
this.registerPlayerPlaceholder("%np_equipped_nameplate-name%", (player) -> {
|
||||
Nameplate nameplate = plugin.getNameplateManager().nameplateById(player.equippedNameplate());
|
||||
return Optional.ofNullable(nameplate).map(Nameplate::displayName).orElse("");
|
||||
});
|
||||
this.registerPlayerPlaceholder("%np_equipped_bubble-name%", (player) -> {
|
||||
BubbleConfig bubble = plugin.getBubbleManager().bubbleConfigById(player.equippedBubble());
|
||||
return Optional.ofNullable(bubble).map(BubbleConfig::displayName).orElse("");
|
||||
});
|
||||
if (ConfigManager.nameplateModule()) {
|
||||
this.registerPlayerPlaceholder("%np_equipped_nameplate%", CNPlayer::equippedNameplate);
|
||||
this.registerPlayerPlaceholder("%np_equipped_nameplate-name%", (player) -> {
|
||||
Nameplate nameplate = plugin.getNameplateManager().nameplateById(player.equippedNameplate());
|
||||
return Optional.ofNullable(nameplate).map(Nameplate::displayName).orElse("");
|
||||
});
|
||||
}
|
||||
if (ConfigManager.bubbleModule()) {
|
||||
this.registerPlayerPlaceholder("%np_equipped_bubble%", CNPlayer::equippedBubble);
|
||||
this.registerPlayerPlaceholder("%np_equipped_bubble-name%", (player) -> {
|
||||
BubbleConfig bubble = plugin.getBubbleManager().bubbleConfigById(player.equippedBubble());
|
||||
return Optional.ofNullable(bubble).map(BubbleConfig::displayName).orElse("");
|
||||
});
|
||||
}
|
||||
|
||||
this.registerSharedPlaceholder("%shared_np_is-latest%", () -> String.valueOf(plugin.isUpToDate()));
|
||||
this.registerPlayerPlaceholder("%np_is-latest%", (player) -> String.valueOf(plugin.isUpToDate()));
|
||||
for (int i = 1; i <= 20; i++) {
|
||||
@@ -184,17 +213,19 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
this.registerPlayerPlaceholder("%np_gradient_" + i + "%", (player) -> {
|
||||
int currentTicks = MainTask.getTicks();
|
||||
double progress = currentTicks * 0.01 * speed;
|
||||
return String.format("%.2f", -1 + (progress % 2.0001));
|
||||
return String.format(Locale.US, "%.2f", -1 + (progress % 2.0001));
|
||||
});
|
||||
}
|
||||
for (int i = 1; i <= 20; i++) {
|
||||
int speed = i;
|
||||
this.registerPlayerPlaceholder("%np_gradient_" + i + "%", (player) -> {
|
||||
this.registerSharedPlaceholder("%shared_np_gradient_" + i + "%", () -> {
|
||||
int currentTicks = MainTask.getTicks();
|
||||
double progress = currentTicks * 0.01 * speed;
|
||||
return String.format("%.2f", -1 + (progress % 2.0001));
|
||||
return String.format(Locale.US, "%.2f", -1 + (progress % 2.0001));
|
||||
});
|
||||
}
|
||||
this.registerPlayerPlaceholder("%np_is_showing%", (player) -> String.valueOf(player.isToggleablePreviewing()));
|
||||
this.registerPlayerPlaceholder("%np_is_previewing%", (player) -> String.valueOf(player.isTempPreviewing()));
|
||||
this.registerPlayerPlaceholder("%np_time%", (player) -> {
|
||||
long time = player.playerTime() % 24_000;
|
||||
String ap = time >= 6000 && time < 18000 ? " PM" : " AM";
|
||||
@@ -205,6 +236,25 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
if (minutes < 10) return hours + ":0" + minutes + ap;
|
||||
else return hours + ":" + minutes + ap;
|
||||
});
|
||||
this.registerPlayerPlaceholder("%np_time_12%", (player) -> {
|
||||
long time = player.playerTime() % 24_000;
|
||||
String ap = time >= 6000 && time < 18000 ? " PM" : " AM";
|
||||
int hours = (int) (time / 1000) ;
|
||||
int minutes = (int) ((time - hours * 1000 ) * 0.06);
|
||||
hours += 6;
|
||||
while (hours >= 12) hours -= 12;
|
||||
if (minutes < 10) return hours + ":0" + minutes + ap;
|
||||
else return hours + ":" + minutes + ap;
|
||||
});
|
||||
this.registerPlayerPlaceholder("%np_time_24%", (player) -> {
|
||||
long time = player.playerTime() % 24_000;
|
||||
int hours = (int) (time / 1000);
|
||||
int minutes = (int) ((time - hours * 1000) * 0.06);
|
||||
hours += 6;
|
||||
if (hours >= 24) hours -= 24;
|
||||
String minuteStr = (minutes < 10) ? "0" + minutes : String.valueOf(minutes);
|
||||
return hours + ":" + minuteStr;
|
||||
});
|
||||
this.registerPlayerPlaceholder("%np_actionbar%", (player) -> Optional.ofNullable(plugin.getActionBarManager().getExternalActionBar(player)).orElse(""));
|
||||
for (Image image : plugin.getImageManager().images()) {
|
||||
this.registerSharedPlaceholder("%shared_np_image_" + image.id() + "%",
|
||||
@@ -291,20 +341,25 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
}
|
||||
|
||||
private void loadVanillaHud(Section section) {
|
||||
if (!ConfigManager.imageModule()) return;
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
String id = entry.getKey();
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
boolean reverse = inner.getBoolean("reverse", true);
|
||||
Image empty = requireNonNull(plugin.getImageManager().imageById(inner.getString("images.empty")), "image.empty should not be null");
|
||||
Image half = requireNonNull(plugin.getImageManager().imageById(inner.getString("images.half")), "image.half should not be null");
|
||||
Image full = requireNonNull(plugin.getImageManager().imageById(inner.getString("images.full")), "image.full should not be null");
|
||||
String currentValue = section.getString("placeholder.value", "1");
|
||||
String maxValue = section.getString("placeholder.max-value", currentValue);
|
||||
Image empty = plugin.getImageManager().imageById(inner.getString("images.empty"));
|
||||
Image half = plugin.getImageManager().imageById(inner.getString("images.half"));
|
||||
Image full = plugin.getImageManager().imageById(inner.getString("images.full"));
|
||||
if (empty == null || half == null || full == null) {
|
||||
plugin.getPluginLogger().warn("Empty/Half/Full image not found in vanilla hud");
|
||||
continue;
|
||||
}
|
||||
String currentValue = inner.getString("placeholder.value", "1");
|
||||
String maxValue = inner.getString("placeholder.max-value", currentValue);
|
||||
VanillaHud vanillaHud = new VanillaHud(empty, half, full, reverse, currentValue, maxValue);
|
||||
List<PreParsedDynamicText> list = List.of(vanillaHud.getCurrent(), vanillaHud.getMax());
|
||||
Placeholder placeholder1 = registerSharedPlaceholder("%shared_np_vanilla_" + id + "%", vanillaHud::create);
|
||||
Placeholder placeholder2 = registerPlayerPlaceholder("%np_vanilla_" + id + "%", vanillaHud::create);
|
||||
Placeholder placeholder3 = registerRelationalPlaceholder("%np_vanilla_" + id + "%", vanillaHud::create);
|
||||
Placeholder placeholder3 = registerRelationalPlaceholder("%rel_np_vanilla_" + id + "%", vanillaHud::create);
|
||||
childrenText.put(placeholder1, list);
|
||||
childrenText.put(placeholder2, list);
|
||||
childrenText.put(placeholder3, list);
|
||||
@@ -320,7 +375,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
PreParsedDynamicText defaultValue = new PreParsedDynamicText(inner.getString("default", ""));
|
||||
ArrayList<PreParsedDynamicText> list = new ArrayList<>();
|
||||
list.add(placeholderToSwitch);
|
||||
this.delayedInitTexts.add(defaultValue);
|
||||
delayedInitTexts.add(defaultValue);
|
||||
Map<String, PreParsedDynamicText> valueMap = new HashMap<>();
|
||||
Section results = inner.getSection("case");
|
||||
if (results != null) {
|
||||
@@ -328,7 +383,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
if (strEntry.getValue() instanceof String string) {
|
||||
PreParsedDynamicText preParsedDynamicText = new PreParsedDynamicText(string);
|
||||
valueMap.put(strEntry.getKey(), preParsedDynamicText);
|
||||
this.delayedInitTexts.add(preParsedDynamicText);
|
||||
delayedInitTexts.add(preParsedDynamicText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,13 +395,13 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
Placeholder placeholder2 = registerPlayerPlaceholder("%np_switch_" + id + "%", (player) -> {
|
||||
String value = placeholderToSwitch.fastCreate(player).render(player);
|
||||
PreParsedDynamicText text = valueMap.getOrDefault(value, defaultValue);
|
||||
player.forceUpdate(text.placeholders(), Collections.emptySet());
|
||||
player.forceUpdatePlaceholders(text.placeholders(), Collections.emptySet());
|
||||
return text.fastCreate(player).render(player);
|
||||
});
|
||||
Placeholder placeholder3 = registerRelationalPlaceholder("%rel_np_switch_" + id + "%", (p1, p2) -> {
|
||||
String value = placeholderToSwitch.fastCreate(p1).render(p2);
|
||||
PreParsedDynamicText text = valueMap.getOrDefault(value, defaultValue);
|
||||
p1.forceUpdate(text.placeholders(), Set.of(p2));
|
||||
p1.forceUpdatePlaceholders(text.placeholders(), Set.of(p2));
|
||||
return text.fastCreate(p1).render(p2);
|
||||
});
|
||||
childrenText.put(placeholder1, list);
|
||||
@@ -357,6 +412,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
}
|
||||
|
||||
private void loadBubbleTextSection(Section section) {
|
||||
if (!ConfigManager.bubbleModule()) return;
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
String id = entry.getKey();
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
@@ -388,13 +444,14 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
childrenText.put(placeholder8, list);
|
||||
childrenText.put(placeholder9, list);
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Nameplate [" + bbID + "] not exists");
|
||||
plugin.getPluginLogger().warn("Bubble [" + bbID + "] not exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadNameplateTextSection(Section section) {
|
||||
if (!ConfigManager.nameplateModule()) return;
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
String id = entry.getKey();
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
@@ -433,6 +490,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
}
|
||||
|
||||
private void loadBackgroundTextSection(Section section) {
|
||||
if (!ConfigManager.backgroundModule()) return;
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
String id = entry.getKey();
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
@@ -481,10 +539,10 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
Requirement[] requirements = plugin.getRequirementManager().parseRequirements(inner.getSection("conditions"));
|
||||
PreParsedDynamicText preParsedDynamicText = new PreParsedDynamicText(text);
|
||||
orderedTexts.add(Pair.of(preParsedDynamicText, requirements));
|
||||
this.delayedInitTexts.add(preParsedDynamicText);
|
||||
delayedInitTexts.add(preParsedDynamicText);
|
||||
}
|
||||
}
|
||||
this.registerSharedPlaceholder("%shared_np_conditional_" + id + "%", () -> {
|
||||
Placeholder placeholder1 = this.registerSharedPlaceholder("%shared_np_conditional_" + id + "%", () -> {
|
||||
outer:
|
||||
for (Pair<PreParsedDynamicText, Requirement[]> orderedText : orderedTexts) {
|
||||
for (Requirement requirement : orderedText.right()) {
|
||||
@@ -496,28 +554,31 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
}
|
||||
return "";
|
||||
});
|
||||
this.registerPlayerPlaceholder("%np_conditional_" + id + "%", (player) -> {
|
||||
Placeholder placeholder2 = this.registerPlayerPlaceholder("%np_conditional_" + id + "%", (player) -> {
|
||||
for (Pair<PreParsedDynamicText, Requirement[]> orderedText : orderedTexts) {
|
||||
if (!player.isMet(orderedText.right())) {
|
||||
continue;
|
||||
}
|
||||
PreParsedDynamicText text = orderedText.left();
|
||||
player.forceUpdate(text.placeholders(), Collections.emptySet());
|
||||
player.forceUpdatePlaceholders(text.placeholders(), Collections.emptySet());
|
||||
return text.fastCreate(player).render(player);
|
||||
}
|
||||
return "";
|
||||
});
|
||||
this.registerRelationalPlaceholder("%rel_np_conditional_" + id + "%", (p1, p2) -> {
|
||||
Placeholder placeholder3 = this.registerRelationalPlaceholder("%rel_np_conditional_" + id + "%", (p1, p2) -> {
|
||||
for (Pair<PreParsedDynamicText, Requirement[]> orderedText : orderedTexts) {
|
||||
if (!p1.isMet(p2, orderedText.right())) {
|
||||
continue;
|
||||
}
|
||||
PreParsedDynamicText text = orderedText.left();
|
||||
p1.forceUpdate(text.placeholders(), Set.of(p2));
|
||||
p1.forceUpdatePlaceholders(text.placeholders(), Set.of(p2));
|
||||
return text.fastCreate(p1).render(p2);
|
||||
}
|
||||
return "";
|
||||
});
|
||||
childrenText.put(placeholder1, List.of());
|
||||
childrenText.put(placeholder2, List.of());
|
||||
childrenText.put(placeholder3, List.of());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -526,20 +587,20 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
public void refreshPlaceholders() {
|
||||
for (CNPlayer player : plugin.getOnlinePlayers()) {
|
||||
if (!player.isOnline()) continue;
|
||||
Set<Feature> featuresToNotifyUpdates = new HashSet<>();
|
||||
Map<Feature, List<CNPlayer>> relationalFeaturesToNotifyUpdates = new HashMap<>();
|
||||
List<Placeholder> placeholdersToUpdate = player.activePlaceholdersToRefresh();
|
||||
List<RelationalPlaceholder> delayedPlaceholdersToUpdate = new ArrayList<>();
|
||||
for (Placeholder placeholder : placeholdersToUpdate) {
|
||||
Set<Feature> featuresToNotifyUpdates = new ObjectOpenHashSet<>();
|
||||
Map<Feature, List<CNPlayer>> relationalFeaturesToNotifyUpdates = new Object2ObjectOpenHashMap<>();
|
||||
List<RelationalPlaceholder> delayedPlaceholdersToUpdate = new ObjectArrayList<>();
|
||||
for (Placeholder placeholder : player.activePlaceholdersToRefresh()) {
|
||||
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
|
||||
TickStampData<String> previous = player.getValue(placeholder);
|
||||
TimeStampData<String> previous = player.getRawPlayerValue(playerPlaceholder);
|
||||
if (previous == null) {
|
||||
String value = playerPlaceholder.request(player);
|
||||
player.setValue(placeholder, new TickStampData<>(value, MainTask.getTicks(), true));
|
||||
player.setPlayerValue(playerPlaceholder, new TimeStampData<>(value, MainTask.getTicks(), true));
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
} else {
|
||||
if (previous.ticks() == MainTask.getTicks()) {
|
||||
if (previous.ticks() > MainTask.getTicks() - getRefreshInterval(placeholder.countId())) {
|
||||
if (previous.hasValueChanged()) {
|
||||
previous.resetChangedFlag();
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
}
|
||||
continue;
|
||||
@@ -547,7 +608,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
String value = playerPlaceholder.request(player);
|
||||
if (!previous.data().equals(value)) {
|
||||
previous.data(value);
|
||||
previous.updateTicks(true);
|
||||
previous.updateTicks(false);
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
} else {
|
||||
previous.updateTicks(false);
|
||||
@@ -556,7 +617,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
} else if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
delayedPlaceholdersToUpdate.add(relationalPlaceholder);
|
||||
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
|
||||
TickStampData<String> previous = player.getValue(placeholder);
|
||||
TimeStampData<String> previous = player.getRawSharedValue(sharedPlaceholder);
|
||||
if (previous == null) {
|
||||
String value;
|
||||
// if the shared placeholder has been updated by other players
|
||||
@@ -565,12 +626,13 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
} else {
|
||||
value = sharedPlaceholder.request();
|
||||
}
|
||||
player.setValue(placeholder, new TickStampData<>(value, MainTask.getTicks(), true));
|
||||
player.setSharedValue(sharedPlaceholder, new TimeStampData<>(value, MainTask.getTicks(), true));
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
} else {
|
||||
// The placeholder has been refreshed by other codes
|
||||
if (previous.ticks() == MainTask.getTicks()) {
|
||||
if (previous.ticks() > MainTask.getTicks() - getRefreshInterval(placeholder.countId())) {
|
||||
if (previous.hasValueChanged()) {
|
||||
previous.resetChangedFlag();
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
}
|
||||
continue;
|
||||
@@ -584,7 +646,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
}
|
||||
if (!previous.data().equals(value)) {
|
||||
previous.data(value);
|
||||
previous.updateTicks(true);
|
||||
previous.updateTicks(false);
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
} else {
|
||||
previous.updateTicks(false);
|
||||
@@ -595,24 +657,25 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
|
||||
for (RelationalPlaceholder placeholder : delayedPlaceholdersToUpdate) {
|
||||
for (CNPlayer nearby : player.nearbyPlayers()) {
|
||||
TickStampData<String> previous = player.getRelationalValue(placeholder, nearby);
|
||||
TimeStampData<String> previous = player.getRawRelationalValue(placeholder, nearby);
|
||||
if (previous == null) {
|
||||
String value = placeholder.request(player, nearby);
|
||||
player.setRelationalValue(placeholder, nearby, new TickStampData<>(value, MainTask.getTicks(), true));
|
||||
player.setRelationalValue(placeholder, nearby, new TimeStampData<>(value, MainTask.getTicks(), true));
|
||||
for (Feature feature : player.activeFeatures(placeholder)) {
|
||||
// Filter features that will not be updated for all players
|
||||
if (!featuresToNotifyUpdates.contains(feature)) {
|
||||
List<CNPlayer> players = relationalFeaturesToNotifyUpdates.computeIfAbsent(feature, k -> new ArrayList<>());
|
||||
List<CNPlayer> players = relationalFeaturesToNotifyUpdates.computeIfAbsent(feature, k -> new ObjectArrayList<>());
|
||||
players.add(nearby);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (previous.ticks() == MainTask.getTicks()) {
|
||||
if (previous.ticks() > MainTask.getTicks() - getRefreshInterval(placeholder.countId())) {
|
||||
if (previous.hasValueChanged()) {
|
||||
previous.resetChangedFlag();
|
||||
for (Feature feature : player.activeFeatures(placeholder)) {
|
||||
// Filter features that will not be updated for all players
|
||||
if (!featuresToNotifyUpdates.contains(feature)) {
|
||||
List<CNPlayer> players = relationalFeaturesToNotifyUpdates.computeIfAbsent(feature, k -> new ArrayList<>());
|
||||
List<CNPlayer> players = relationalFeaturesToNotifyUpdates.computeIfAbsent(feature, k -> new ObjectArrayList<>());
|
||||
players.add(nearby);
|
||||
}
|
||||
}
|
||||
@@ -622,11 +685,11 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
String value = placeholder.request(player, nearby);
|
||||
if (!previous.data().equals(value)) {
|
||||
previous.data(value);
|
||||
previous.updateTicks(true);
|
||||
previous.updateTicks(false);
|
||||
for (Feature feature : player.activeFeatures(placeholder)) {
|
||||
// Filter features that will not be updated for all players
|
||||
if (!featuresToNotifyUpdates.contains(feature)) {
|
||||
List<CNPlayer> players = relationalFeaturesToNotifyUpdates.computeIfAbsent(feature, k -> new ArrayList<>());
|
||||
List<CNPlayer> players = relationalFeaturesToNotifyUpdates.computeIfAbsent(feature, k -> new ObjectArrayList<>());
|
||||
players.add(nearby);
|
||||
}
|
||||
}
|
||||
@@ -656,18 +719,27 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRefreshInterval(int countId) {
|
||||
return fasterRefreshIntervals.getOrDefault(countId, ConfigManager.defaultPlaceholderRefreshInterval());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRefreshInterval(String id) {
|
||||
return refreshIntervals.getOrDefault(id, ConfigManager.defaultRefreshInterval());
|
||||
return refreshIntervals.getOrDefault(id, ConfigManager.defaultPlaceholderRefreshInterval());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Placeholder> T registerPlaceholder(T placeholder) {
|
||||
Placeholder nested = nestedPlaceholders.get(placeholder.id());
|
||||
if (nested != null) {
|
||||
placeholder.addChildren(nested.children());
|
||||
for (Placeholder child : nested.children()) {
|
||||
placeholder.addChild(child);
|
||||
child.addParent(placeholder);
|
||||
}
|
||||
}
|
||||
registeredPlaceholders.put(placeholder.id(), placeholder);
|
||||
fasterRefreshIntervals.put(placeholder.countId(), placeholder.refreshInterval());
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
@@ -713,7 +785,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
if (firstPercent == 0 && text.charAt(text.length() - 1) == '%' && text.indexOf('%', 1) == text.length() - 1) {
|
||||
return Collections.singletonList(text);
|
||||
}
|
||||
List<String> placeholders = new ArrayList<>();
|
||||
List<String> placeholders = new ObjectArrayList<>();
|
||||
Matcher m = PATTERN.matcher(text);
|
||||
while (m.find()) {
|
||||
placeholders.add(m.group());
|
||||
|
||||
+13
@@ -17,16 +17,29 @@
|
||||
|
||||
package net.momirealms.customnameplates.backend.requirement;
|
||||
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class AbstractRequirement implements Requirement {
|
||||
|
||||
protected final int refreshInterval;
|
||||
@Nullable
|
||||
protected Integer countId;
|
||||
|
||||
public AbstractRequirement(int refreshInterval) {
|
||||
this.refreshInterval = refreshInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countId() {
|
||||
// lazy init
|
||||
if (countId == null) {
|
||||
countId = CustomNameplates.getInstance().getRequirementManager().countId(this);
|
||||
}
|
||||
return countId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refreshInterval() {
|
||||
return refreshInterval;
|
||||
|
||||
+43
-7
@@ -18,6 +18,9 @@
|
||||
package net.momirealms.customnameplates.backend.requirement;
|
||||
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
|
||||
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||
@@ -25,15 +28,21 @@ import net.momirealms.customnameplates.api.requirement.RequirementFactory;
|
||||
import net.momirealms.customnameplates.api.requirement.RequirementManager;
|
||||
import net.momirealms.customnameplates.api.util.ConfigUtils;
|
||||
import net.momirealms.customnameplates.backend.requirement.builtin.*;
|
||||
import net.momirealms.customnameplates.common.util.ListUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
|
||||
protected final CustomNameplates plugin;
|
||||
private final HashMap<String, RequirementFactory> requirementFactoryMap = new HashMap<>();
|
||||
private final Object2ObjectOpenHashMap<String, RequirementFactory> requirementFactoryMap = new Object2ObjectOpenHashMap<>(128);
|
||||
private int countId = 0;
|
||||
private final Map<Requirement, Integer> registeredRequirements = new Object2IntOpenHashMap<>(128);
|
||||
|
||||
public AbstractRequirementManager(CustomNameplates plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -41,7 +50,23 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
this.registerPlatformRequirements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
this.countId = 0;
|
||||
this.registeredRequirements.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countId(Requirement requirement) {
|
||||
if (requirement == null) return -1;
|
||||
if (this.registeredRequirements.containsKey(requirement)) return this.registeredRequirements.get(requirement);
|
||||
this.countId++;
|
||||
this.registeredRequirements.put(requirement, countId);
|
||||
return this.countId;
|
||||
}
|
||||
|
||||
private void registerInternalRequirements() {
|
||||
this.registerRequirement((args, interval) -> new LaggyRequirement(interval, (int) args), "laggy");
|
||||
this.registerRequirement((args, interval) -> {
|
||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||
if (section == null) return Requirement.empty();
|
||||
@@ -99,10 +124,17 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
this.registerRequirement((args, interval) -> {
|
||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||
if (section == null) return Requirement.empty();
|
||||
PreParsedDynamicText dynamicText1 = new PreParsedDynamicText(section.getString("value1", ""), true);
|
||||
String regex = section.getString("value2", "");
|
||||
PreParsedDynamicText dynamicText1 = new PreParsedDynamicText(section.getString("papi", ""), true);
|
||||
String regex = section.getString("regex", "");
|
||||
return new RegexRequirement(interval, dynamicText1, regex);
|
||||
}, "regex");
|
||||
this.registerRequirement((args, interval) -> {
|
||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||
if (section == null) return Requirement.empty();
|
||||
PreParsedDynamicText dynamicText1 = new PreParsedDynamicText(section.getString("papi", ""), true);
|
||||
String regex = section.getString("regex", "");
|
||||
return new NotRegexRequirement(interval, dynamicText1, regex);
|
||||
}, "!regex");
|
||||
this.registerRequirement((args, interval) -> {
|
||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||
if (section == null) return Requirement.empty();
|
||||
@@ -137,7 +169,7 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
PreParsedDynamicText dynamicText1 = new PreParsedDynamicText(section.getString("value1", ""), true);
|
||||
PreParsedDynamicText dynamicText2 = new PreParsedDynamicText(section.getString("value2", ""), true);
|
||||
return new NumberEqualsRequirement(interval, dynamicText1, dynamicText2);
|
||||
}, "=");
|
||||
}, "=", "==");
|
||||
this.registerRequirement((args, interval) -> {
|
||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||
if (section == null) return Requirement.empty();
|
||||
@@ -177,6 +209,10 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
boolean has = (boolean) args;
|
||||
return new HasBubbleRequirement(interval, has);
|
||||
}, "has-bubble");
|
||||
this.registerRequirement((args, interval) -> new NameplateRequirement(interval, new HashSet<>(ListUtils.toList(args))), "nameplate");
|
||||
this.registerRequirement((args, interval) -> new NotNameplateRequirement(interval, new HashSet<>(ListUtils.toList(args))), "!nameplate");
|
||||
this.registerRequirement((args, interval) -> new BubbleRequirement(interval, new HashSet<>(ListUtils.toList(args))), "bubble");
|
||||
this.registerRequirement((args, interval) -> new NotBubbleRequirement(interval, new HashSet<>(ListUtils.toList(args))), "!bubble");
|
||||
}
|
||||
|
||||
protected abstract void registerPlatformRequirements();
|
||||
@@ -248,7 +284,7 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
plugin.getPluginLogger().warn("Requirement type: " + type + " not exists");
|
||||
return Requirement.empty();
|
||||
}
|
||||
return factory.process(section.get("value"), section.getInt("refresh-interval", 10));
|
||||
return factory.process(section.get("value"), section.getInt("refresh-interval", ConfigManager.defaultConditionRefreshInterval()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -258,6 +294,6 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
plugin.getPluginLogger().warn("Requirement type: " + type + " doesn't exist.");
|
||||
return Requirement.empty();
|
||||
}
|
||||
return factory.process(value, 10);
|
||||
return factory.process(value, ConfigManager.defaultConditionRefreshInterval());
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class BubbleRequirement extends AbstractRequirement {
|
||||
|
||||
private final Set<String> bubbles;
|
||||
|
||||
public BubbleRequirement(int refreshInterval, Set<String> bubbles) {
|
||||
super(refreshInterval);
|
||||
this.bubbles = bubbles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.bubbleModule()) return false;
|
||||
String bubble = p1.equippedBubble();
|
||||
if (bubble.equals("none")) bubble = CustomNameplates.getInstance().getBubbleManager().defaultBubbleId();
|
||||
return bubbles.contains(bubble);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "bubble";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof BubbleRequirement that)) return false;
|
||||
return bubbles.equals(that.bubbles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(bubbles);
|
||||
}
|
||||
}
|
||||
+2
@@ -18,6 +18,7 @@
|
||||
package net.momirealms.customnameplates.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
@@ -32,6 +33,7 @@ public class HasBubbleRequirement extends AbstractRequirement {
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.bubbleModule()) return !has;
|
||||
String bubble = p1.equippedBubble();
|
||||
if (bubble.equals("none")) bubble = CustomNameplates.getInstance().getBubbleManager().defaultBubbleId();
|
||||
if (has) {
|
||||
|
||||
+2
@@ -18,6 +18,7 @@
|
||||
package net.momirealms.customnameplates.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
@@ -32,6 +33,7 @@ public class HasNameplateRequirement extends AbstractRequirement {
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.nameplateModule()) return !has;
|
||||
String nameplate = p1.equippedNameplate();
|
||||
if (nameplate.equals("none")) nameplate = CustomNameplates.getInstance().getNameplateManager().defaultNameplateId();
|
||||
if (has) {
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
public class LaggyRequirement extends AbstractRequirement {
|
||||
|
||||
private final int time;
|
||||
|
||||
public LaggyRequirement(int refreshInterval, int time) {
|
||||
super(refreshInterval);
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.debug()) return true;
|
||||
long time1 = System.currentTimeMillis();
|
||||
while (true) {
|
||||
if (System.currentTimeMillis() - time1 > time) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "laggy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type().hashCode() + time * 17;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof LaggyRequirement that)) return false;
|
||||
return time == that.time;
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class NameplateRequirement extends AbstractRequirement {
|
||||
|
||||
private final Set<String> nameplates;
|
||||
|
||||
public NameplateRequirement(int refreshInterval, Set<String> nameplates) {
|
||||
super(refreshInterval);
|
||||
this.nameplates = nameplates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.nameplateModule()) return false;
|
||||
String nameplate = p1.equippedNameplate();
|
||||
if (nameplate.equals("none")) nameplate = CustomNameplates.getInstance().getNameplateManager().defaultNameplateId();
|
||||
return nameplates.contains(nameplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "nameplate";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof NameplateRequirement that)) return false;
|
||||
return nameplates.equals(that.nameplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(nameplates);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class NotBubbleRequirement extends AbstractRequirement {
|
||||
|
||||
private final Set<String> bubbles;
|
||||
|
||||
public NotBubbleRequirement(int refreshInterval, Set<String> bubbles) {
|
||||
super(refreshInterval);
|
||||
this.bubbles = bubbles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.bubbleModule()) return false;
|
||||
String bubble = p1.equippedBubble();
|
||||
if (bubble.equals("none")) bubble = CustomNameplates.getInstance().getBubbleManager().defaultBubbleId();
|
||||
return !bubbles.contains(bubble);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "!bubble";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof NotBubbleRequirement that)) return false;
|
||||
return bubbles.equals(that.bubbles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(bubbles);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class NotNameplateRequirement extends AbstractRequirement {
|
||||
|
||||
private final Set<String> nameplates;
|
||||
|
||||
public NotNameplateRequirement(int refreshInterval, Set<String> nameplates) {
|
||||
super(refreshInterval);
|
||||
this.nameplates = nameplates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
if (!ConfigManager.nameplateModule()) return false;
|
||||
String nameplate = p1.equippedNameplate();
|
||||
if (nameplate.equals("none")) nameplate = CustomNameplates.getInstance().getNameplateManager().defaultNameplateId();
|
||||
return !nameplates.contains(nameplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "!nameplate";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof NotNameplateRequirement that)) return false;
|
||||
return nameplates.equals(that.nameplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(nameplates);
|
||||
}
|
||||
}
|
||||
+37
@@ -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.backend.requirement.builtin;
|
||||
|
||||
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
|
||||
|
||||
public class NotRegexRequirement extends PlaceholderRequirement<String> {
|
||||
|
||||
public NotRegexRequirement(int refreshInterval, PreParsedDynamicText text, String any) {
|
||||
super(refreshInterval, text, any);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkArgument(String a1, String a2) {
|
||||
return !a1.matches(a2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "!regex";
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -37,7 +37,7 @@ public abstract class PlaceholderRequirement<T> extends AbstractRequirement {
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
p1.forceUpdate(text.placeholders(), Set.of(p2));
|
||||
p1.forceUpdatePlaceholders(text.placeholders(), Set.of(p2));
|
||||
String a1 = text.fastCreate(p1).render(p2);
|
||||
return checkArgument(a1, any);
|
||||
}
|
||||
|
||||
+3
-2
@@ -37,8 +37,9 @@ public abstract class PlaceholdersRequirement extends AbstractRequirement {
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
p1.forceUpdate(t1.placeholders(), Set.of(p2));
|
||||
p1.forceUpdate(t2.placeholders(), Set.of(p2));
|
||||
Set<CNPlayer> set = Set.of(p2);
|
||||
p1.forceUpdatePlaceholders(t1.placeholders(), set);
|
||||
p1.forceUpdatePlaceholders(t2.placeholders(), set);
|
||||
String a1 = t1.fastCreate(p1).render(p2);
|
||||
String a2 = t2.fastCreate(p1).render(p2);
|
||||
return checkArgument(a1, a2);
|
||||
|
||||
+7
-5
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -94,6 +95,7 @@ public class StorageManagerImpl implements StorageManager, JoinQuitListener {
|
||||
private void handleDataLoad(CNPlayer player, PlayerData data) {
|
||||
player.equippedBubble(data.bubble());
|
||||
player.equippedNameplate(data.nameplate());
|
||||
plugin.getUnlimitedTagManager().togglePreviewing(player, data.previewTags());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,7 +113,7 @@ public class StorageManagerImpl implements StorageManager, JoinQuitListener {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// Check if storage type has changed and reinitialize if necessary
|
||||
StorageType storageType = StorageType.valueOf(config.getString("data-storage-method", "H2"));
|
||||
StorageType storageType = StorageType.valueOf(config.getString("data-storage-method", "H2").toUpperCase(Locale.ENGLISH));
|
||||
if (storageType != previousType) {
|
||||
if (this.dataSource != null) this.dataSource.disable();
|
||||
this.previousType = storageType;
|
||||
@@ -119,10 +121,10 @@ public class StorageManagerImpl implements StorageManager, JoinQuitListener {
|
||||
case H2 -> this.dataSource = new H2Provider(plugin);
|
||||
case JSON -> this.dataSource = new JsonProvider(plugin);
|
||||
case YAML -> this.dataSource = new YAMLProvider(plugin);
|
||||
case SQLite -> this.dataSource = new SQLiteProvider(plugin);
|
||||
case MySQL -> this.dataSource = new MySQLProvider(plugin);
|
||||
case MariaDB -> this.dataSource = new MariaDBProvider(plugin);
|
||||
case MongoDB -> this.dataSource = new MongoDBProvider(plugin);
|
||||
case SQLITE -> this.dataSource = new SQLiteProvider(plugin);
|
||||
case MYSQL -> this.dataSource = new MySQLProvider(plugin);
|
||||
case MARIADB -> this.dataSource = new MariaDBProvider(plugin);
|
||||
case MONGODB -> this.dataSource = new MongoDBProvider(plugin);
|
||||
case NONE -> this.dataSource = new DummyStorage(plugin);
|
||||
}
|
||||
if (this.dataSource != null) this.dataSource.initialize(config);
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public class MongoDBProvider extends AbstractStorage {
|
||||
|
||||
@Override
|
||||
public StorageType storageType() {
|
||||
return StorageType.MongoDB;
|
||||
return StorageType.MONGODB;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -21,14 +21,14 @@ public abstract class AbstractHikariDatabase extends AbstractSQLDatabase {
|
||||
|
||||
public AbstractHikariDatabase(CustomNameplates plugin) {
|
||||
super(plugin);
|
||||
this.driverClass = storageType() == StorageType.MariaDB ? "org.mariadb.jdbc.Driver" : "com.mysql.cj.jdbc.Driver";
|
||||
this.sqlBrand = storageType() == StorageType.MariaDB ? "MariaDB" : "MySQL";
|
||||
this.driverClass = storageType() == StorageType.MARIADB ? "org.mariadb.jdbc.Driver" : "com.mysql.cj.jdbc.Driver";
|
||||
this.sqlBrand = storageType() == StorageType.MARIADB ? "MariaDB" : "MySQL";
|
||||
try {
|
||||
Class.forName(this.driverClass);
|
||||
} catch (ClassNotFoundException e1) {
|
||||
if (storageType() == StorageType.MariaDB) {
|
||||
if (storageType() == StorageType.MARIADB) {
|
||||
plugin.getPluginLogger().warn("No MariaDB driver is found");
|
||||
} else if (storageType() == StorageType.MySQL) {
|
||||
} else if (storageType() == StorageType.MYSQL) {
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
} catch (ClassNotFoundException e2) {
|
||||
|
||||
+1
-1
@@ -11,6 +11,6 @@ public class MariaDBProvider extends AbstractHikariDatabase {
|
||||
|
||||
@Override
|
||||
public StorageType storageType() {
|
||||
return StorageType.MariaDB;
|
||||
return StorageType.MARIADB;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -11,6 +11,6 @@ public class MySQLProvider extends AbstractHikariDatabase {
|
||||
|
||||
@Override
|
||||
public StorageType storageType() {
|
||||
return StorageType.MySQL;
|
||||
return StorageType.MYSQL;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -63,7 +63,7 @@ public class SQLiteProvider extends AbstractSQLDatabase {
|
||||
|
||||
@Override
|
||||
public StorageType storageType() {
|
||||
return StorageType.SQLite;
|
||||
return StorageType.SQLITE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#version 150
|
||||
#moj_import<fog.glsl>
|
||||
#moj_import <fog.glsl>
|
||||
|
||||
uniform sampler2D Sampler0;
|
||||
uniform vec4 ColorModulator;
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#version 150
|
||||
#moj_import<fog.glsl>
|
||||
#moj_import <fog.glsl>
|
||||
|
||||
uniform sampler2D Sampler0;
|
||||
uniform vec4 ColorModulator;
|
||||
|
||||
-5
@@ -1,9 +1,4 @@
|
||||
{
|
||||
"blend": {
|
||||
"func": "add",
|
||||
"srcrgb": "srcalpha",
|
||||
"dstrgb": "1-srcalpha"
|
||||
},
|
||||
"vertex": "rendertype_text",
|
||||
"fragment": "rendertype_text",
|
||||
"attributes": [
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#version 150
|
||||
#moj_import <minecraft:fog.glsl>
|
||||
|
||||
uniform sampler2D Sampler0;
|
||||
uniform vec4 ColorModulator;
|
||||
uniform float FogStart,FogEnd;
|
||||
uniform vec4 FogColor;
|
||||
uniform float GameTime;
|
||||
|
||||
in float vertexDistance;
|
||||
in vec4 vertexColor;
|
||||
in vec2 texCoord0;
|
||||
in float depthLevel;
|
||||
%SHADER_0%
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 texColor = texture(Sampler0, texCoord0);
|
||||
vec4 color = texColor * vertexColor * ColorModulator;%SHADER_1%
|
||||
if (color.a < 0.1) {
|
||||
discard;
|
||||
}
|
||||
if (depthLevel == 114514.0) {
|
||||
discard;
|
||||
}
|
||||
if (texColor.a == 254.0/255.0) {
|
||||
if (depthLevel == 1000.0
|
||||
|| depthLevel == 2200
|
||||
|| depthLevel == 50
|
||||
|| depthLevel == 2650
|
||||
|| depthLevel == 200
|
||||
|| depthLevel == 400
|
||||
|| depthLevel == 2800
|
||||
|| depthLevel == 2400
|
||||
) {
|
||||
discard;
|
||||
} else {
|
||||
color = vec4(texColor.rgb, 1.0) * vertexColor * ColorModulator;
|
||||
}
|
||||
}
|
||||
fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor);
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"vertex": "minecraft:core/rendertype_text",
|
||||
"fragment": "minecraft:core/rendertype_text",
|
||||
"attributes": [
|
||||
"Position",
|
||||
"Color",
|
||||
"UV0",
|
||||
"UV2"
|
||||
],
|
||||
"samplers": [
|
||||
{ "name": "Sampler0" },
|
||||
{ "name": "Sampler2" }
|
||||
],
|
||||
"uniforms": [
|
||||
{ "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||
{ "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] },
|
||||
{ "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] },
|
||||
{ "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] },
|
||||
{ "name": "GameTime", "type": "float", "count": 1, "values": [ 1.0 ] },
|
||||
{ "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] }
|
||||
]
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#version 150
|
||||
#moj_import <minecraft:fog.glsl>
|
||||
|
||||
in vec3 Position;
|
||||
in vec4 Color;
|
||||
in vec2 UV0;
|
||||
in ivec2 UV2;
|
||||
|
||||
uniform sampler2D Sampler2;
|
||||
uniform mat4 ModelViewMat;
|
||||
uniform mat4 ProjMat;
|
||||
uniform float GameTime;
|
||||
uniform int FogShape;
|
||||
uniform vec2 ScreenSize;
|
||||
|
||||
out float vertexDistance;
|
||||
out vec4 vertexColor;
|
||||
out vec2 texCoord0;
|
||||
out float depthLevel;
|
||||
%SHADER_0%
|
||||
void main() {
|
||||
vec4 vertex = vec4(Position, 1.0);
|
||||
vertexDistance = fog_distance(Position, FogShape);
|
||||
depthLevel = Position.z;
|
||||
texCoord0 = UV0;
|
||||
%SHADER_1%%SHADER_2%%SHADER_3%
|
||||
}
|
||||
@@ -1,21 +1,28 @@
|
||||
{
|
||||
"pack":{
|
||||
"pack_format": 8,
|
||||
"description":"CustomNameplates",
|
||||
"supported_formats": {
|
||||
"min_inclusive": 8,
|
||||
"max_inclusive": 34
|
||||
"pack": {
|
||||
"pack_format": 13,
|
||||
"description": "CustomNameplates",
|
||||
"supported_formats": {
|
||||
"min_inclusive": 13,
|
||||
"max_inclusive": 46
|
||||
}
|
||||
},
|
||||
"overlays": {
|
||||
"entries": [
|
||||
{
|
||||
"formats": {
|
||||
"min_inclusive": 32,
|
||||
"max_inclusive": 34
|
||||
},
|
||||
"directory": "overlay_1_20_5"
|
||||
},
|
||||
{
|
||||
"formats": {
|
||||
"min_inclusive": 42,
|
||||
"max_inclusive": 46
|
||||
},
|
||||
"directory": "overlay_1_21_2"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overlays": {
|
||||
"entries": [
|
||||
{
|
||||
"formats": {
|
||||
"min_inclusive": 32,
|
||||
"max_inclusive": 34
|
||||
},
|
||||
"directory": "overlay_1_20_5"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,28 @@
|
||||
{
|
||||
"pack":{
|
||||
"pack_format": 32,
|
||||
"description":"CustomNameplates",
|
||||
"supported_formats": {
|
||||
"min_inclusive": 32,
|
||||
"max_inclusive": 34
|
||||
"pack": {
|
||||
"pack_format": 32,
|
||||
"description": "CustomNameplates",
|
||||
"supported_formats": {
|
||||
"min_inclusive": 32,
|
||||
"max_inclusive": 46
|
||||
}
|
||||
},
|
||||
"overlays": {
|
||||
"entries": [
|
||||
{
|
||||
"formats": {
|
||||
"min_inclusive": 32,
|
||||
"max_inclusive": 34
|
||||
},
|
||||
"directory": "overlay_1_20_5"
|
||||
},
|
||||
{
|
||||
"formats": {
|
||||
"min_inclusive": 42,
|
||||
"max_inclusive": 46
|
||||
},
|
||||
"directory": "overlay_1_21_2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"pack": {
|
||||
"pack_format": 42,
|
||||
"description": "CustomNameplates",
|
||||
"supported_formats": {
|
||||
"min_inclusive": 42,
|
||||
"max_inclusive": 46
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,16 @@ nameplates_preview:
|
||||
usage:
|
||||
- /nameplates preview
|
||||
|
||||
# A command to toggle the nameplate previewing
|
||||
# This command conflicts with `/nameplates preview`
|
||||
# You should never enable both of them at the same time
|
||||
# Usage: [COMMAND]
|
||||
nameplates_toggle:
|
||||
enable: false
|
||||
permission: nameplates.command.toggle
|
||||
usage:
|
||||
- /nameplates toggle
|
||||
|
||||
# A command to view the available nameplates
|
||||
# Usage: [COMMAND]
|
||||
nameplates_list:
|
||||
@@ -133,4 +143,12 @@ bubbles_list:
|
||||
enable: true
|
||||
permission: bubbles.command.list
|
||||
usage:
|
||||
- /bubbles list
|
||||
- /bubbles list
|
||||
|
||||
# A command to test some stuffs
|
||||
# Usage: [COMMAND]
|
||||
debug_test:
|
||||
enable: false
|
||||
permission: nameplates.command.debug.test
|
||||
usage:
|
||||
- /nameplates debug test
|
||||
@@ -8,101 +8,84 @@ metrics: true
|
||||
update-checker: true
|
||||
# Forces a specific locale (e.g., zh_cn)
|
||||
force-locale: ''
|
||||
# Module Settings
|
||||
# Modifying these modules may result in distorted images. If this occurs, reinstall the newly generated resource pack.
|
||||
|
||||
# Module Settings: Enable or disable specific features.
|
||||
modules:
|
||||
nameplates: true
|
||||
backgrounds: true
|
||||
bubbles: true
|
||||
bossbars: true
|
||||
actionbars: true
|
||||
images: true
|
||||
# Plugin Integrations
|
||||
nametags: true # Enable name tags
|
||||
nameplates: true # Enable nameplates
|
||||
backgrounds: true # Enable background images for nameplates
|
||||
bubbles: true # Enable bubble text display
|
||||
bossbars: true # Enable bossbars
|
||||
actionbars: true # Enable actionbars
|
||||
images: true # Enable image displays
|
||||
|
||||
# Plugin Integrations: Integrate resource packs and chat plugins with other plugins.
|
||||
integrations:
|
||||
# Should Nameplates merge resource packs with these plugins during reload?
|
||||
resource-pack:
|
||||
ItemsAdder: false
|
||||
ItemsAdder-old-method: false
|
||||
Oraxen: false
|
||||
# Some chats, such as staff chats or menu inputs, may need to be excluded from capture.
|
||||
# Supported chat plugins are listed below, which allow blacklist channels and /ignore functionality to work correctly.
|
||||
ItemsAdder: false # Integration with ItemsAdder
|
||||
ItemsAdder-old-method: false # Legacy integration with ItemsAdder
|
||||
Oraxen: false # Integration with Oraxen
|
||||
Nexo: false # Integration with Nexo
|
||||
Creative-Central: false # Integration with Creative-Central
|
||||
chat:
|
||||
TrChat: false
|
||||
VentureChat: false
|
||||
HuskChat: false
|
||||
CarbonChat: false
|
||||
AdvancedChat: false
|
||||
Essentials: false
|
||||
# Resource Pack Generation Settings
|
||||
TrChat: false # Integration with TrChat
|
||||
VentureChat: false # Integration with VentureChat
|
||||
HuskChat: false # Integration with HuskChat
|
||||
CarbonChat: false # Integration with CarbonChat
|
||||
AdvancedChat: false # Integration with AdvancedChat
|
||||
Essentials: false # Integration with Essentials chat
|
||||
ChatControlRed: false # Integration with ChatControlRed
|
||||
Chatty: false # Integration with Chatty
|
||||
|
||||
# Resource Pack Generation Settings: Configure resource pack generation behavior.
|
||||
resource-pack:
|
||||
# Disables resource pack generation at server startup
|
||||
disable-generation-on-start: false
|
||||
# Namespace identifier
|
||||
namespace: "nameplates"
|
||||
# Font selection
|
||||
font: "default"
|
||||
# The starting character for custom fonts
|
||||
# This character is used, but it won't affect normal Korean characters during chat, as they belong to the "minecraft:default" font.
|
||||
initial-char: '뀁'
|
||||
# Specify directories for PNG file generation.
|
||||
# This helps maintain an organized resource pack structure.
|
||||
image-path:
|
||||
nameplates: 'font/nameplates/'
|
||||
backgrounds: 'font/backgrounds/'
|
||||
images: 'font/images/'
|
||||
bubbles: 'font/bubbles/'
|
||||
space-split: 'font/base/'
|
||||
# Shader Settings
|
||||
disable-generation-on-start: false # Allow resource pack generation at server start
|
||||
namespace: "nameplates" # Namespace for the resource pack
|
||||
font: "default" # Default font used
|
||||
initial-char: '뀁' # Starting character for custom fonts (won't affect Korean characters in chat)
|
||||
image-path: # Paths for different assets
|
||||
nameplates: 'font/nameplates/' # Path for nameplates assets
|
||||
backgrounds: 'font/backgrounds/' # Path for background images
|
||||
images: 'font/images/' # Path for other images
|
||||
bubbles: 'font/bubbles/' # Path for bubble text images
|
||||
space-split: 'font/base/' # Path for base font images
|
||||
shader:
|
||||
# Enables shader generation
|
||||
enable: true
|
||||
# Hides scoreboard numbers (1.20.4- requires shader to remove that)
|
||||
hide-scoreboard-number: false
|
||||
# Enables support for animated text shaders
|
||||
animated-text: false
|
||||
# Enables ItemsAdder text effect support
|
||||
ItemsAdder-text-effects: false
|
||||
# Bossbar transparency settings
|
||||
enable: true # Enable shader generation
|
||||
hide-scoreboard-number: false # Hiding of scoreboard numbers
|
||||
animated-text: false # Animated text shaders
|
||||
ItemsAdder-text-effects: false # ItemsAdder text effects support
|
||||
transparent-bossbar:
|
||||
# Specify the color of the bossbar to hide
|
||||
color: YELLOW
|
||||
# Generate transparent bossbars for Minecraft 1.20.2+
|
||||
"1_20_2+": true
|
||||
# Generate transparent bossbars for Minecraft 1.17-1.20.1
|
||||
"1_17-1_20_1": true
|
||||
# Legacy Unicode support for Minecraft 1.20+ clients, as these images were removed in 1.20, affecting the creation of decent texts.
|
||||
# Enabling this increases your resource pack size by approximately 900KB.
|
||||
legacy-unicodes: true
|
||||
# Additional Settings
|
||||
color: YELLOW # BossBar color to remove
|
||||
"1_20_2+": true # Enable transparent bossbar for Minecraft 1.20.2+
|
||||
"1_17-1_20_1": true # Enable transparent bossbar for Minecraft 1.17-1.20.1
|
||||
legacy-unicodes: true # Enable legacy Unicode support for Minecraft 1.20+ (increases resource pack size by 900KB)
|
||||
|
||||
# Additional Settings: Extra options to control behavior and performance.
|
||||
other-settings:
|
||||
# It is recommended to use the MiniMessage format. If you prefer legacy color codes using "&", enable this support.
|
||||
# Disabling it will improve color formatting performance.
|
||||
legacy-color-code-support: true
|
||||
# Set a delay for actionbar/bossbar to prevent compatibility issues
|
||||
send-delay: 0
|
||||
# Determines whether CustomNameplates should capture actionbars from other plugins
|
||||
catch-other-plugin-actionbar: true
|
||||
# Should the plugin listen for chat canceled events by unknown chat plugins?
|
||||
unsafe-chat-event: false
|
||||
# Set the default placeholder refresh interval
|
||||
default-placeholder-refresh-interval: 1
|
||||
# Set the refresh interval for better performance in ticks (Especially for those heavy placeholders)
|
||||
placeholder-refresh-interval:
|
||||
legacy-color-code-support: true # Enable support for legacy color codes using &
|
||||
send-delay: 20 # Set actionbar/bossbar send delay (ticks) (0 = send immediately on async threads, -1 = send immediately on main thread)
|
||||
catch-other-plugin-actionbar: true # Capture actionbars from other plugins
|
||||
other-actionbar-stay-time: 3000 # How long does other actionsbars stay (ms)
|
||||
display-system-actionbar: true # Should the plugin display system actionbar and temporarily hide the custom actionbar?
|
||||
hide-team-names: true # Hide the team name sent by other plugins or vanilla team system
|
||||
unsafe-chat-event: false # Listen for canceled(unsafe) chat events from unknown plugins
|
||||
default-condition-refresh-interval: 10 # Set default condition refresh interval in ticks
|
||||
default-placeholder-refresh-interval: 1 # Set default placeholder refresh interval in ticks
|
||||
placeholder-refresh-interval: # Custom placeholder refresh intervals for performance optimization
|
||||
"%player_name%": 100
|
||||
"%vault_prefix%": 1
|
||||
# CustomNameplates provides some templates for reading the default Minecraft fonts
|
||||
# You can replace the files under /font or add new configuration to let the plugin get these templates.
|
||||
# Templates can be used in advance-data.yml
|
||||
"%vault_prefix%": 20
|
||||
# Font Templates: Define different fonts and their settings.
|
||||
# Requires a restart to apply because it can be laggy to read thousands of character
|
||||
font-templates:
|
||||
space:
|
||||
space:
|
||||
" ": 4
|
||||
"\\u200c": 0
|
||||
" ": 4 # Define space width as 4 units
|
||||
"\\u200c": 0 # Define zero-width non-joiner as 0 width
|
||||
unihex:
|
||||
unifont:
|
||||
file: unifont.zip
|
||||
generate: false
|
||||
size_overrides:
|
||||
file: unifont.zip # Load font from unifont.zip
|
||||
generate: false # Should this unihex file be included in the generated pack
|
||||
size_overrides: # Override size for specific Unicode ranges
|
||||
- from: "\\u3001"
|
||||
to: "\\u30FF"
|
||||
left: 0
|
||||
@@ -140,10 +123,10 @@ other-settings:
|
||||
left: 0
|
||||
right: 15
|
||||
unifont_jp:
|
||||
file: unifont_jp.zip
|
||||
generate: false
|
||||
file: unifont_jp.zip # Load Japanese unifont
|
||||
generate: false # Should this unihex file be included in the generated pack
|
||||
filter:
|
||||
"jp": true
|
||||
"jp": true # Apply to Japanese characters only
|
||||
size_overrides:
|
||||
- from: "\\u3200"
|
||||
to: "\\u9FFF"
|
||||
@@ -155,10 +138,12 @@ other-settings:
|
||||
right: 15
|
||||
bitmap:
|
||||
ascii:
|
||||
codepoints: ascii
|
||||
file: ascii.png
|
||||
height: 8
|
||||
custom: false # Is this a non-default Minecraft font? If enabled, plugin will create a new font image in the generated resource pack
|
||||
codepoints: ascii # Define ASCII bitmap font
|
||||
file: ascii.png # Use ascii.png file for the font
|
||||
height: 8 # Font height is 8 units
|
||||
custom: false # Does this png path point to a non-default font path??
|
||||
generate: false # Should this png file be included in the generated pack
|
||||
# namespace: custom # Optional namespace if you don't want to use the global namespace set in config.yml
|
||||
ascii_sga:
|
||||
codepoints: ascii_sga
|
||||
file: ascii_sga.png
|
||||
@@ -181,33 +166,35 @@ other-settings:
|
||||
custom: false
|
||||
legacy_unicode:
|
||||
legacy_unicode:
|
||||
file: unicode_page_%02x.png
|
||||
height: 8
|
||||
file: unicode_page_%02x.png # Legacy Unicode characters page file
|
||||
height: 8 # Set height to 8 units
|
||||
custom: false
|
||||
unicode:
|
||||
unicode:
|
||||
file: unicode_page_%02x.png
|
||||
sizes: glyph_sizes.bin
|
||||
ttf:
|
||||
example:
|
||||
generate: false
|
||||
file: example.ttf
|
||||
size: 10.0
|
||||
oversample: 8.0
|
||||
skip: []
|
||||
# If the font is a bitmap font, the number represents the ascent
|
||||
# If the font is a ttf font, the number represents the Y shift
|
||||
file: unicode_page_%02x.png # Default Unicode characters
|
||||
sizes: glyph_sizes.bin # Glyph size configuration
|
||||
ttf: {}
|
||||
# ttf:
|
||||
# example:
|
||||
# generate: false # Should this TTF file be included in the generated pack
|
||||
# file: example.ttf # Define the TTF file to load the font from
|
||||
# size: 10.0 # Set font size
|
||||
# oversample: 8.0 # Oversample rate for TTF rendering
|
||||
# skip: [] # Skipped characters in list format
|
||||
shift-fonts:
|
||||
shift_0:
|
||||
- space
|
||||
- nonlatin_european:7
|
||||
- accented:9
|
||||
- ascii:7
|
||||
- unifont_jp
|
||||
#- unifont_jp
|
||||
- unifont
|
||||
shift_1:
|
||||
- space
|
||||
- nonlatin_european:3
|
||||
- accented:6
|
||||
- ascii:3
|
||||
- legacy_unicode:3
|
||||
- legacy_unicode:3
|
||||
shift_2:
|
||||
- space
|
||||
- ascii:-15
|
||||
@@ -1,24 +1,13 @@
|
||||
# Important: Players can only see one actionbar at any given moment, no overlap allowed!
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/config/actionbar.yml
|
||||
actionbar:
|
||||
# Players need this permission to display the actionbar, the conditions can be customized
|
||||
conditions:
|
||||
condition_1:
|
||||
type: permission
|
||||
refresh-interval: 20 # Refresh rate, in ticks, to recheck the permission status
|
||||
refresh-interval: 20
|
||||
value:
|
||||
- actionbar.show
|
||||
text-display-order:
|
||||
1:
|
||||
# Duration of the text display, measured in ticks (20 ticks = 1 second)
|
||||
# -1 means the text will stay on the screen forever!
|
||||
duration: -1
|
||||
# The message to be shown in the actionbar
|
||||
text: '%np_conditional_actionbar%'
|
||||
# Optional settings for finer control:
|
||||
# When enabling conditions, make sure at least one valid actionbar is displayed to the player,
|
||||
# or it may lead to an endless loop with nothing visible.
|
||||
# If the player doesn't meet the condition, this actionbar will simply be skipped.
|
||||
# The condition is only checked once per cycle, until the next time it comes around.
|
||||
conditions: {}
|
||||
#2: ...
|
||||
#3: ...
|
||||
conditions: {}
|
||||
@@ -1,15 +1,13 @@
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/config/advance-data.yml
|
||||
# namespace:font
|
||||
minecraft:default:
|
||||
# default advance
|
||||
default: 9.0
|
||||
# Sets the loading sequence of the templates
|
||||
template-loading-sequence:
|
||||
- unifont
|
||||
- nonlatin_european
|
||||
- accented
|
||||
- ascii
|
||||
- space
|
||||
# The values here would override the same character in the template
|
||||
values:
|
||||
默: 9.0
|
||||
|
||||
|
||||
@@ -1,39 +1,25 @@
|
||||
# You can create as many bossbar sections as you'd like
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/config/bossbar.yml
|
||||
bossbar_1:
|
||||
# Choose the color of the bossbar (Options: BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW)
|
||||
color: YELLOW
|
||||
# Decide how the progress bar looks (Options: "progress", "notched_6", "notched_10", "notched_12", "notched_20")
|
||||
overlay: PROGRESS
|
||||
conditions:
|
||||
condition_1:
|
||||
type: permission
|
||||
refresh-interval: 20 # How often, in ticks, to check if the player still has the required permission
|
||||
refresh-interval: 20
|
||||
value:
|
||||
- bossbar.show
|
||||
# The bossbar will cycle through the text in this exact order:
|
||||
text-display-order:
|
||||
1:
|
||||
# Time (in ticks) this text stays on the screen (100 ticks = 5 seconds)
|
||||
duration: 100
|
||||
# What message to display in the bossbar
|
||||
text: '%np_background_hello%'
|
||||
2:
|
||||
# Display for 10 seconds
|
||||
duration: 200
|
||||
text: '%np_background_time% %np_background_location% %np_background_weather%'
|
||||
# How often to refresh this text, in ticks (1 tick = 1/20 of a second)
|
||||
refresh-frequency: 1
|
||||
3:
|
||||
# Show for 5 seconds
|
||||
duration: 100
|
||||
text: '%np_background_update%'
|
||||
# Optional extra control:
|
||||
# Make sure at least one bossbar message is shown, or else it could result in an endless cycle with nothing visible!
|
||||
# If the player doesn’t meet the condition, this message will be skipped.
|
||||
# Conditions are only checked once per cycle until it comes back around.
|
||||
conditions:
|
||||
permission: nameplates.admin # Only players with this permission will see this specific message
|
||||
permission: nameplates.admin
|
||||
equals:
|
||||
# Compare two values and act based on the result
|
||||
value1: '%np_is-latest%'
|
||||
value2: 'false' # Only display if the value is "false"
|
||||
value2: 'false'
|
||||
@@ -1,35 +1,21 @@
|
||||
# Requirements for sending the bubble
|
||||
# Do not modify this value
|
||||
config-version: '${config_version}'
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/config/bubble.yml
|
||||
sender-requirements:
|
||||
permission: bubbles.send
|
||||
'!gamemode': spectator
|
||||
potion-effect: "INVISIBILITY<0"
|
||||
|
||||
viewer-requirements:
|
||||
permission: bubbles.see
|
||||
|
||||
# blacklist channels
|
||||
blacklist-channels:
|
||||
- Private
|
||||
- Staff
|
||||
|
||||
# ALL: all the players can see the bubble
|
||||
# JOINED: players in the same channel can see each other's bubble
|
||||
# CAN_JOIN: players that have permission to certain channels would see the bubble in that channel
|
||||
channel-mode: ALL
|
||||
|
||||
# Default bubble to display if player's bubble is "none"
|
||||
default-bubble: 'chat'
|
||||
|
||||
# Y offset from the highest nameplate
|
||||
y-offset: 0.1
|
||||
|
||||
view-range: 0.5
|
||||
|
||||
# Bubble display time (in ticks)
|
||||
stay-duration: 150
|
||||
appear-duration: 4
|
||||
disappear-duration: 2
|
||||
|
||||
bubble-settings:
|
||||
chat:
|
||||
display-name: "White Bubbles"
|
||||
@@ -40,5 +26,5 @@ bubble-settings:
|
||||
3: chat_3
|
||||
line-width: 150
|
||||
background-color: 0,0,0,0
|
||||
text-prefix: "<black><font:nameplates:shift_0>"
|
||||
text-prefix: "<black><font:{namespace}:shift_0>" # {namespace} would be replaced by the namespace set in config.yml
|
||||
text-suffix: "</font></black>"
|
||||
@@ -2,21 +2,37 @@
|
||||
conditional-text:
|
||||
actionbar:
|
||||
priority_1:
|
||||
text: '%np_background_other_actionbar%'
|
||||
text: '%np_background_other_actionbar%' # hides the money hud when a player rides something or dives in water
|
||||
conditions:
|
||||
'||':
|
||||
'!=':
|
||||
value1: '%player_remaining_air%'
|
||||
value2: "300"
|
||||
'!gamemode': survival
|
||||
condition_or:
|
||||
type: "||"
|
||||
refresh-interval: 1
|
||||
value:
|
||||
condition_passenger:
|
||||
type: is-passenger
|
||||
refresh-interval: 1
|
||||
value: true
|
||||
condition_air:
|
||||
type: "!="
|
||||
refresh-interval: 1
|
||||
value:
|
||||
value1: '%player_remaining_air%'
|
||||
value2: "300"
|
||||
condition_gamemode:
|
||||
type: "!gamemode"
|
||||
refresh-interval: 1
|
||||
value: survival
|
||||
priority_2:
|
||||
text: '%np_static_money_hud%%np_offset_-180%%np_static_other_actionbar%'
|
||||
text: '%np_static_money_hud%%np_offset_-179%%np_static_other_actionbar%' # displays the money hud + other plugin's actionbar message
|
||||
conditions:
|
||||
'!equals':
|
||||
value1: '%np_actionbar%'
|
||||
value2: ""
|
||||
condition_other_actionbar:
|
||||
type: "!equals"
|
||||
refresh-interval: 1
|
||||
value:
|
||||
value1: '%np_actionbar%'
|
||||
value2: ""
|
||||
priority_3:
|
||||
text: '%np_static_money_hud%'
|
||||
text: '%np_static_money_hud%' # displays the money hud only
|
||||
weather:
|
||||
priority_1:
|
||||
text: 'Sunny'
|
||||
@@ -34,7 +50,15 @@ conditional-text:
|
||||
weather:
|
||||
- thunder
|
||||
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/custom-placeholders/nameplate-text
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/custom-placeholders/background-nameplate-bubble-text
|
||||
bubble-text:
|
||||
chat:
|
||||
bubble: chat_1
|
||||
text: '<black>Nice to meet you!</black>'
|
||||
left-margin: 1
|
||||
right-margin: 1
|
||||
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/custom-placeholders/background-nameplate-bubble-text
|
||||
nameplate-text:
|
||||
halloween:
|
||||
nameplate: halloween
|
||||
@@ -42,7 +66,7 @@ nameplate-text:
|
||||
left-margin: 1
|
||||
right-margin: 1
|
||||
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/custom-placeholders/background-text
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/custom-placeholders/background-nameplate-bubble-text
|
||||
background-text:
|
||||
location:
|
||||
background: bedrock_1
|
||||
@@ -101,7 +125,7 @@ shift-text:
|
||||
text: "Your Location: %np_switch_world% (%player_x%,%player_y%,%player_z%)"
|
||||
font: shift_1
|
||||
time:
|
||||
text: "Time: %np_time%"
|
||||
text: "Time: %np_time_12%"
|
||||
font: shift_1
|
||||
weather:
|
||||
text: "Weather: %np_conditional_weather%"
|
||||
@@ -109,12 +133,12 @@ shift-text:
|
||||
update:
|
||||
text: "A newer version of CustomNameplates is available!"
|
||||
font: shift_1
|
||||
money:
|
||||
text: "%vault_eco_balance%"
|
||||
font: shift_1
|
||||
hello:
|
||||
text: "Hello 여보세요 你好 こんにちは, Thanks for using CustomNameplates"
|
||||
font: shift_1
|
||||
money:
|
||||
text: "%vault_eco_balance%"
|
||||
font: shift_2
|
||||
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/custom-placeholders/switch-text
|
||||
switch-text:
|
||||
@@ -122,30 +146,32 @@ switch-text:
|
||||
switch: "%np_equipped_nameplate%"
|
||||
default: ""
|
||||
case:
|
||||
'wither': "<gradient:#FF0000:#000000:%np_gradient_3%>"
|
||||
'halloween': "<gradient:#FF0000:#000000:%np_gradient_3%>"
|
||||
'hutao': "<gradient:#FFFFFF:#FF4500:%np_gradient_3%>"
|
||||
'rabbit': "<gradient:#FFFFFF:#DB7093:%np_gradient_3%>"
|
||||
'starsky': "<gradient:#FFFFF0:#696969:%np_gradient_3%>"
|
||||
'trident': "<gradient:#E1FFFF:#008B8B:%np_gradient_10%>"
|
||||
'cheems': "<gradient:#C0C0C0:#F5F5F5:%np_gradient_5%>"
|
||||
'egg': "<gradient:#FFFFFF:#FFA500:%np_gradient_5%>"
|
||||
'cat': "<gradient:#FFFFFF:#1E90FF:%np_gradient_5%>"
|
||||
'xmas': "<gradient:#FFFFFF:#FF4500:%np_gradient_5%>"
|
||||
'xmas': "<WHITE>"
|
||||
'angel': "<#8B4513>"
|
||||
'sign': "<BLACK>"
|
||||
'banner': "<WHITE>"
|
||||
'enter': "<WHITE>"
|
||||
nameplate_color_suffix:
|
||||
switch: "%np_equipped_nameplate%"
|
||||
default: ""
|
||||
case:
|
||||
'wither': "</gradient>"
|
||||
'halloween': "</gradient>"
|
||||
'hutao': "</gradient>"
|
||||
'rabbit': "</gradient>"
|
||||
'starsky': "</gradient>"
|
||||
'trident': "</gradient>"
|
||||
'cheems': "</gradient>"
|
||||
'egg': "</gradient>"
|
||||
'cat': "</gradient>"
|
||||
'xmas': "</gradient>"
|
||||
'xmas': "</WHITE>"
|
||||
'angel': "</#8B4513>"
|
||||
'sign': "</BLACK>"
|
||||
'banner': "</WHITE>"
|
||||
'enter': "</WHITE>"
|
||||
world:
|
||||
switch: '%player_world%'
|
||||
case:
|
||||
|
||||
@@ -1,67 +1,50 @@
|
||||
# Duration (in seconds) for which the nameplate preview will be displayed.
|
||||
# Do not modify this value
|
||||
config-version: '${config_version}'
|
||||
# https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates/config/nameplate.yml
|
||||
preview-duration: 5
|
||||
|
||||
# Default nameplate shown when a player's nameplate is set to "none."
|
||||
default-nameplate: 'none'
|
||||
|
||||
# Whether to make the nameplate always visible to the player
|
||||
always-show: false
|
||||
|
||||
# Configuration for nameplate behavior and appearance.
|
||||
nameplate:
|
||||
# Prefix to be displayed before the player's name.
|
||||
# The prefix here will become part of the nameplate
|
||||
prefix: '%np_switch_nameplate_color_prefix%'
|
||||
# Placeholder for the player's name
|
||||
# The default configuration uses shift to ensure that the player name not affected by the clientside `force-unicode-font` setting.
|
||||
player-name: '%np_shift_player_name%'
|
||||
# Suffix to be displayed after the player's name.
|
||||
# The suffix here will become part of the nameplate
|
||||
suffix: '%np_switch_nameplate_color_suffix%'
|
||||
|
||||
# Configuration for Unlimited tags.
|
||||
unlimited:
|
||||
tag_1:
|
||||
text: '%np_tag-image%'
|
||||
translation: 0,0.2,0
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
condition_potion:
|
||||
type: potion-effect
|
||||
value: "INVISIBILITY<0"
|
||||
refresh-interval: 1
|
||||
self-disguised: false
|
||||
affected-by-crouching: true
|
||||
affected-by-scale-attribute: true
|
||||
line-width: 1024
|
||||
background-color: 0,0,0,0
|
||||
tag_2:
|
||||
text: '%np_tag-text%'
|
||||
translation: 0.01,0.2,0.01
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
has-nameplate: true
|
||||
condition_potion:
|
||||
type: potion-effect
|
||||
value: "INVISIBILITY<0"
|
||||
refresh-interval: 1
|
||||
self-disguised: false
|
||||
affected-by-crouching: true
|
||||
affected-by-scale-attribute: true
|
||||
line-width: 1024
|
||||
background-color: 0,0,0,0
|
||||
tag_3:
|
||||
tag_normal:
|
||||
text: '%np_tag-text%'
|
||||
translation: 0,0.2,0
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
has-nameplate: false
|
||||
condition_potion:
|
||||
type: potion-effect
|
||||
value: "INVISIBILITY<0"
|
||||
refresh-interval: 1
|
||||
potion-effect: "INVISIBILITY<0"
|
||||
self-disguised: false
|
||||
affected-by-crouching: true
|
||||
affected-by-scale-attribute: true
|
||||
affected-by-spectator: true
|
||||
line-width: 1024
|
||||
background-color: 64,0,0,0
|
||||
background-color: 64,0,0,0
|
||||
tag_image_part:
|
||||
text: '%np_tag-image%'
|
||||
translation: 0,0.2,0
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
has-nameplate: true
|
||||
potion-effect: "INVISIBILITY<0"
|
||||
self-disguised: false
|
||||
affected-by-crouching: true
|
||||
affected-by-scale-attribute: true
|
||||
affected-by-spectator: true
|
||||
line-width: 1024
|
||||
background-color: 0,0,0,0
|
||||
tag_text_part:
|
||||
text: '%np_tag-text%'
|
||||
translation: 0.01,0.2,0.01
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
has-nameplate: true
|
||||
potion-effect: "INVISIBILITY<0"
|
||||
self-disguised: false
|
||||
affected-by-crouching: true
|
||||
affected-by-scale-attribute: true
|
||||
affected-by-spectator: true
|
||||
line-width: 1024
|
||||
background-color: 0,0,0,0
|
||||
@@ -1,6 +1,4 @@
|
||||
image: bell
|
||||
height: 10
|
||||
ascent: 4
|
||||
shadow:
|
||||
remove: true
|
||||
opacity: 254
|
||||
shadow: false
|
||||
@@ -1,6 +1,4 @@
|
||||
image: bubble
|
||||
height: 10
|
||||
ascent: 4
|
||||
shadow:
|
||||
remove: true
|
||||
opacity: 254
|
||||
shadow: false
|
||||
@@ -1,6 +1,4 @@
|
||||
image: clock
|
||||
height: 10
|
||||
ascent: 4
|
||||
shadow:
|
||||
remove: true
|
||||
opacity: 254
|
||||
shadow: false
|
||||
Loaded 100 of 268 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user