Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fe8625722 | ||
|
|
43e006f49d | ||
|
|
8d63ad9c74 | ||
|
|
5c2411e420 | ||
|
|
a57cfb0842 | ||
|
|
e4d7fb4346 | ||
|
|
9a9865c424 | ||
|
|
f6b8ce253f | ||
|
|
144b358768 | ||
|
|
0fd7ac1a79 | ||
|
|
67f0e60327 | ||
|
|
d10eb6de67 | ||
|
|
8cfd098be9 | ||
|
|
e3d81e7c0c | ||
|
|
018dc18eee | ||
|
|
366cda6bef | ||
|
|
ca70dfb2b4 | ||
|
|
d59ac96f48 |
No files matched your search
@@ -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
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ dependencies {
|
||||
compileOnly("io.netty:netty-all:4.1.113.Final")
|
||||
// GSON
|
||||
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
|
||||
// Fast util
|
||||
compileOnly("it.unimi.dsi:fastutil:${rootProject.properties["fastutil_version"]}")
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
package net.momirealms.customnameplates.api;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
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.TimeStampData;
|
||||
import net.momirealms.customnameplates.api.feature.tag.TeamView;
|
||||
@@ -29,6 +32,7 @@ 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;
|
||||
@@ -51,11 +55,11 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
|
||||
private final TeamView teamView = new TeamView();
|
||||
|
||||
private final Map<Integer, TimeStampData<String>> cachedValues = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, TimeStampData<String>> cachedValues = new ConcurrentHashMap<>(128);
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>(128);
|
||||
|
||||
private final Map<Requirement, TimeStampData<Boolean>> cachedRequirements = new ConcurrentHashMap<>();
|
||||
private final Map<Requirement, WeakHashMap<CNPlayer, TimeStampData<Boolean>>> cachedRelationalRequirements = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, TimeStampData<Boolean>> cachedRequirements = new Int2ObjectOpenHashMap<>(32);
|
||||
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<Boolean>>> cachedRelationalRequirements = new Int2ObjectOpenHashMap<>(32);
|
||||
|
||||
private final Set<Feature> activeFeatures = new CopyOnWriteArraySet<>();
|
||||
private final Map<Placeholder, Set<Feature>> placeholder2Features = new ConcurrentHashMap<>();
|
||||
@@ -71,71 +75,90 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
@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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
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 forceUpdatePlaceholders(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) {
|
||||
TimeStampData<String> value = getValue(placeholder);
|
||||
if (value == null) {
|
||||
value = new TimeStampData<>(playerPlaceholder.request(this), MainTask.getTicks(), true);
|
||||
setValue(placeholder, value);
|
||||
continue;
|
||||
}
|
||||
if (value.ticks() != MainTask.getTicks()) {
|
||||
String newValue = playerPlaceholder.request(this);
|
||||
value.updateTicks(!value.data().equals(newValue));
|
||||
value.data(newValue);
|
||||
}
|
||||
} else if (placeholder instanceof RelationalPlaceholder relational) {
|
||||
for (CNPlayer player : others) {
|
||||
TimeStampData<String> value = getRelationalValue(placeholder, player);
|
||||
if (value == null) {
|
||||
value = new TimeStampData<>(relational.request(this, player), MainTask.getTicks(), true);
|
||||
setRelationalValue(placeholder, player, value);
|
||||
continue;
|
||||
}
|
||||
if (value.ticks() != MainTask.getTicks()) {
|
||||
String newValue = relational.request(this, player);
|
||||
value.updateTicks(!value.data().equals(newValue));
|
||||
value.data(newValue);
|
||||
}
|
||||
}
|
||||
updatePlayerPlaceholder(playerPlaceholder);
|
||||
} else if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
updateRelationalPlaceholder(relationalPlaceholder, others);
|
||||
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
|
||||
TimeStampData<String> value = getValue(placeholder);
|
||||
if (value == null) {
|
||||
String latest;
|
||||
if (MainTask.hasRequested(sharedPlaceholder.countId())) {
|
||||
latest = sharedPlaceholder.getLatestValue();
|
||||
} else {
|
||||
latest = sharedPlaceholder.request();
|
||||
}
|
||||
value = new TimeStampData<>(latest, MainTask.getTicks(), true);
|
||||
setValue(placeholder, value);
|
||||
continue;
|
||||
}
|
||||
if (value.ticks() != MainTask.getTicks()) {
|
||||
String latest;
|
||||
if (MainTask.hasRequested(sharedPlaceholder.countId())) {
|
||||
latest = sharedPlaceholder.getLatestValue();
|
||||
} else {
|
||||
latest = sharedPlaceholder.request();
|
||||
}
|
||||
value.updateTicks(!value.data().equals(latest));
|
||||
value.data(latest);
|
||||
}
|
||||
updateSharedPlaceholder(sharedPlaceholder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +247,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
Set<Placeholder> allPlaceholders = feature.allPlaceholders();
|
||||
feature2Placeholders.put(feature, allPlaceholders);
|
||||
for (Placeholder placeholder : allPlaceholders) {
|
||||
Set<Feature> featureSet = placeholder2Features.computeIfAbsent(placeholder, k -> new HashSet<>());
|
||||
Set<Feature> featureSet = placeholder2Features.computeIfAbsent(placeholder, k -> new ObjectOpenHashSet<>());
|
||||
featureSet.add(feature);
|
||||
}
|
||||
}
|
||||
@@ -243,84 +266,98 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Placeholder placeholder, TimeStampData<String> value) {
|
||||
public void setPlayerValue(PlayerPlaceholder placeholder, TimeStampData<String> value) {
|
||||
cachedValues.put(placeholder.countId(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setValue(Placeholder placeholder, String value) {
|
||||
TimeStampData<String> previous = cachedValues.get(placeholder.countId());
|
||||
int currentTicks = MainTask.getTicks();
|
||||
boolean changed = false;
|
||||
if (previous != null) {
|
||||
if (previous.ticks() == currentTicks) {
|
||||
return false;
|
||||
}
|
||||
String data = previous.data();
|
||||
if (!data.equals(value)) {
|
||||
changed = true;
|
||||
previous.data(value);
|
||||
previous.updateTicks(true);
|
||||
}
|
||||
} else {
|
||||
changed= true;
|
||||
previous = new TimeStampData<>(value, currentTicks, true);
|
||||
cachedValues.put(placeholder.countId(), previous);
|
||||
}
|
||||
return changed;
|
||||
public void setSharedValue(SharedPlaceholder placeholder, TimeStampData<String> value) {
|
||||
cachedValues.put(placeholder.countId(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRelationalValue(Placeholder placeholder, CNPlayer another, TimeStampData<String> value) {
|
||||
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, 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;
|
||||
public @NotNull String getCachedSharedValue(SharedPlaceholder placeholder) {
|
||||
return updateSharedPlaceholder(placeholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getData(Placeholder placeholder) {
|
||||
return Optional.ofNullable(cachedValues.get(placeholder.countId())).map(TimeStampData::data).orElse(placeholder.id());
|
||||
public @NotNull String getCachedPlayerValue(PlayerPlaceholder placeholder) {
|
||||
return updatePlayerPlaceholder(placeholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeStampData<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, TimeStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
|
||||
if (map == null) {
|
||||
return placeholder.id();
|
||||
}
|
||||
return Optional.ofNullable(map.get(another)).map(TimeStampData::data).orElse(placeholder.id());
|
||||
public TimeStampData<String> getRawSharedValue(SharedPlaceholder placeholder) {
|
||||
return cachedValues.get(placeholder.countId());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TimeStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another) {
|
||||
public TimeStampData<String> getRawRelationalValue(RelationalPlaceholder placeholder, CNPlayer another) {
|
||||
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
|
||||
if (map == null) {
|
||||
return null;
|
||||
@@ -330,7 +367,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());
|
||||
}
|
||||
@@ -341,7 +378,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
public boolean isMet(Requirement[] requirements) {
|
||||
int currentTicks = MainTask.getTicks();
|
||||
for (Requirement requirement : requirements) {
|
||||
TimeStampData<Boolean> data = cachedRequirements.get(requirement);
|
||||
TimeStampData<Boolean> data = cachedRequirements.get(requirement.countId());
|
||||
if (data != null) {
|
||||
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
|
||||
if (!data.data()) {
|
||||
@@ -358,7 +395,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
} else {
|
||||
boolean satisfied = requirement.isSatisfied(this, this);
|
||||
data = new TimeStampData<>(satisfied, currentTicks, true);
|
||||
cachedRequirements.put(requirement, data);
|
||||
cachedRequirements.put(requirement.countId(), data);
|
||||
if (!satisfied) {
|
||||
return false;
|
||||
}
|
||||
@@ -371,7 +408,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
public boolean isMet(CNPlayer another, Requirement[] requirements) {
|
||||
int currentTicks = MainTask.getTicks();
|
||||
for (Requirement requirement : requirements) {
|
||||
WeakHashMap<CNPlayer, TimeStampData<Boolean>> innerMap = cachedRelationalRequirements.computeIfAbsent(requirement, k -> new WeakHashMap<>());
|
||||
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) {
|
||||
@@ -406,12 +443,12 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
// for (Placeholder placeholder : activePlaceholders()) {
|
||||
// if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
// String value = relationalPlaceholder.request(this, another);
|
||||
// setRelationalValue(relationalPlaceholder, another, value);
|
||||
// }
|
||||
// }
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@@ -421,8 +458,8 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CNPlayer> nearbyPlayers() {
|
||||
return new HashSet<>(trackers.keySet());
|
||||
public Collection<CNPlayer> nearbyPlayers() {
|
||||
return new ObjectArrayList<>(trackers.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -446,7 +483,7 @@ public abstract class AbstractCNPlayer implements CNPlayer {
|
||||
|
||||
@Override
|
||||
public Set<Integer> getTrackedPassengerIds(CNPlayer another) {
|
||||
return Optional.ofNullable(trackers.get(another)).map(Tracker::getPassengerIDs).orElse(new HashSet<>());
|
||||
return Optional.ofNullable(trackers.get(another)).map(Tracker::getPassengerIDs).orElse(new ObjectOpenHashSet<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,11 +23,15 @@ 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;
|
||||
@@ -190,7 +194,7 @@ public interface CNPlayer {
|
||||
* @param placeholders the placeholders to update
|
||||
* @param another the players related to the placeholders
|
||||
*/
|
||||
void forceUpdatePlaceholders(Set<Placeholder> placeholders, Set<CNPlayer> another);
|
||||
void forceUpdatePlaceholders(Set<Placeholder> placeholders, Collection<CNPlayer> another);
|
||||
|
||||
/**
|
||||
* Retrieves the cached data for a given placeholder.
|
||||
@@ -199,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 TimeStampData} 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
|
||||
TimeStampData<String> getValue(Placeholder placeholder);
|
||||
@NotNull
|
||||
String getCachedPlayerValue(PlayerPlaceholder placeholder);
|
||||
|
||||
/**
|
||||
* Retrieves the cached relational data between this player and another for a given placeholder.
|
||||
@@ -218,7 +222,25 @@ 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 {@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.
|
||||
@@ -228,7 +250,7 @@ public interface CNPlayer {
|
||||
* @return the cached relational TickStampData, or null if none exists
|
||||
*/
|
||||
@Nullable
|
||||
TimeStampData<String> getRelationalValue(Placeholder placeholder, CNPlayer another);
|
||||
TimeStampData<String> getRawRelationalValue(RelationalPlaceholder placeholder, CNPlayer another);
|
||||
|
||||
/**
|
||||
* Caches the specified {@link TimeStampData} for the given placeholder.
|
||||
@@ -236,16 +258,15 @@ public interface CNPlayer {
|
||||
* @param placeholder the placeholder to cache
|
||||
* @param value the value to cache
|
||||
*/
|
||||
void setValue(Placeholder placeholder, TimeStampData<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 TimeStampData} for a given placeholder and player.
|
||||
@@ -254,17 +275,26 @@ public interface CNPlayer {
|
||||
* @param another the other player
|
||||
* @param value the value to cache
|
||||
*/
|
||||
void setRelationalValue(Placeholder placeholder, CNPlayer another, TimeStampData<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
|
||||
@@ -317,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.
|
||||
@@ -401,4 +431,11 @@ public interface CNPlayer {
|
||||
* @return team view
|
||||
*/
|
||||
TeamView teamView();
|
||||
|
||||
/**
|
||||
* Check if the player is initialized
|
||||
*
|
||||
* @return initialized or not
|
||||
*/
|
||||
boolean isInitialized();
|
||||
}
|
||||
@@ -217,7 +217,7 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
|
||||
// Other settings
|
||||
delaySend = config.getInt("other-settings.send-delay", 0);
|
||||
defaultPlaceholderRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 1);
|
||||
defaultConditionRefreshInterval = config.getInt("other-settings.ddefault-condition-refresh-interval", 1);
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
@@ -39,8 +41,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;
|
||||
@@ -69,7 +69,7 @@ public abstract class CustomNameplates implements NameplatesPlugin {
|
||||
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;
|
||||
@@ -288,7 +288,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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,7 +30,7 @@ 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;
|
||||
|
||||
@@ -17,18 +17,23 @@
|
||||
|
||||
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.*;
|
||||
import java.util.ArrayList;
|
||||
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) {
|
||||
@@ -50,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);
|
||||
}
|
||||
@@ -86,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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
@@ -80,6 +87,7 @@ public class NameplateImpl implements Nameplate {
|
||||
@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());
|
||||
@@ -99,6 +107,7 @@ 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());
|
||||
@@ -108,6 +117,7 @@ public class NameplateImpl implements Nameplate {
|
||||
@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());
|
||||
@@ -131,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) {
|
||||
@@ -144,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;
|
||||
@@ -164,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
|
||||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class TeamView {
|
||||
|
||||
private final HashMap<String, Set<String>> teamMembers = new HashMap<>();
|
||||
private final Map<String, Set<String>> teamMembers = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
@Nullable
|
||||
public Set<String> getTeamMembers(String team) {
|
||||
@@ -34,7 +35,7 @@ public class TeamView {
|
||||
}
|
||||
|
||||
public void addTeamMembers(String team, Collection<String> members) {
|
||||
teamMembers.computeIfAbsent(team, k -> new HashSet<>(members));
|
||||
teamMembers.computeIfAbsent(team, k -> new ObjectOpenHashSet<>(members));
|
||||
}
|
||||
|
||||
public void removeTeamMembers(String team, Collection<String> members) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -80,7 +80,7 @@ public class Tracker {
|
||||
}
|
||||
|
||||
public Set<Integer> getPassengerIDs() {
|
||||
return new HashSet<>(passengerIDs);
|
||||
return new ObjectOpenHashSet<>(passengerIDs);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
package net.momirealms.customnameplates.api.placeholder;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -29,8 +29,8 @@ public abstract class AbstractPlaceholder implements Placeholder {
|
||||
protected int countId = PlaceholderCounter.getAndIncrease();
|
||||
protected int refreshInterval;
|
||||
protected PlaceholderManager manager;
|
||||
protected Set<Placeholder> children = new HashSet<>();
|
||||
protected Set<Placeholder> parents = new HashSet<>();
|
||||
protected Set<Placeholder> children = new ObjectOpenHashSet<>();
|
||||
protected Set<Placeholder> parents = new ObjectOpenHashSet<>();
|
||||
|
||||
protected AbstractPlaceholder(PlaceholderManager manager, String id, int refreshInterval) {
|
||||
if (refreshInterval == 0) {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -26,4 +26,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"]}")
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
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;
|
||||
@@ -31,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;
|
||||
@@ -177,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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -584,7 +586,7 @@ 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 ? ConfigManager.namespace() + ":font/" + file : "minecraft:font/" + codePoints + ".png";
|
||||
plugin.getConfigManager().saveResource("tmp/" + codePoints + ".json");
|
||||
StringBuilder jsonContent = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(new File(plugin.getDataDirectory().toFile(), "tmp" + File.separator + codePoints + ".json")))) {
|
||||
@@ -931,7 +933,7 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
.advance(dataMap)
|
||||
.fontProviderFunction(function)
|
||||
.build();
|
||||
charFontWidthDataMap.put(id, fontWidthData);
|
||||
this.charFontWidthDataMap.put(id, fontWidthData);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1019,8 +1021,8 @@ public class AdvanceManagerImpl implements AdvanceManager {
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.textWidthCache.invalidateAll();
|
||||
this.configFontWidthDataMap.clear();
|
||||
this.textWidthCache.cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1216,15 +1218,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();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
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;
|
||||
@@ -27,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 {
|
||||
|
||||
@@ -57,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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ 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;
|
||||
@@ -51,7 +53,7 @@ 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;
|
||||
@@ -62,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;
|
||||
@@ -94,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
|
||||
@@ -231,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());
|
||||
@@ -305,6 +307,7 @@ 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -18,9 +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;
|
||||
@@ -29,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 {
|
||||
@@ -59,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() {
|
||||
@@ -73,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),
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
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;
|
||||
@@ -61,7 +62,7 @@ public class NameplateManagerImpl implements NameplateManager {
|
||||
|
||||
@Override
|
||||
public Collection<Nameplate> nameplates() {
|
||||
return new HashSet<>(nameplates.values());
|
||||
return new ObjectArrayList<>(nameplates.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,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),
|
||||
@@ -136,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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -321,11 +322,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);
|
||||
}
|
||||
@@ -583,6 +626,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" +
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -195,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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -37,6 +38,7 @@ public class TagRendererImpl implements TagRenderer {
|
||||
private Tag[] tagArray;
|
||||
private Tag[] rTagsArray;
|
||||
private double hatOffset;
|
||||
private boolean valid = true;
|
||||
|
||||
public TagRendererImpl(UnlimitedTagManager manager, CNPlayer owner) {
|
||||
this.owner = owner;
|
||||
@@ -68,15 +70,23 @@ public class TagRendererImpl implements TagRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
HashSet<CNPlayer> playersToUpdatePassengers = new HashSet<>();
|
||||
HashSet<CNPlayer> tagTranslationUpdates = new HashSet<>();
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public 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 (tag.isShown()) {
|
||||
for (CNPlayer nearby : owner.nearbyPlayers()) {
|
||||
for (CNPlayer nearby : nearbyPlayers) {
|
||||
if (tag.isShown(nearby)) {
|
||||
if (!tag.canShow(nearby)) {
|
||||
tag.hide(nearby);
|
||||
@@ -97,7 +107,7 @@ public class TagRendererImpl implements TagRenderer {
|
||||
tag.init();
|
||||
tag.tick();
|
||||
tag.show();
|
||||
for (CNPlayer nearby : owner.nearbyPlayers()) {
|
||||
for (CNPlayer nearby : nearbyPlayers) {
|
||||
if (tag.canShow(nearby) && !tag.isShown(nearby)) {
|
||||
tag.show(nearby);
|
||||
playersToUpdatePassengers.add(nearby);
|
||||
@@ -110,7 +120,7 @@ public class TagRendererImpl implements TagRenderer {
|
||||
if (tag.isShown()) {
|
||||
tag.hide();
|
||||
if (!tag.relativeTranslation())
|
||||
tagTranslationUpdates.addAll(owner.nearbyPlayers());
|
||||
tagTranslationUpdates.addAll(nearbyPlayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,6 +143,7 @@ public class TagRendererImpl implements TagRenderer {
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.valid = false;
|
||||
for (Tag tag : this.tagArray) {
|
||||
tag.hide();
|
||||
if (tag instanceof Feature feature) {
|
||||
|
||||
@@ -140,14 +140,16 @@ 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();
|
||||
}
|
||||
if (isAlwaysShow()) {
|
||||
setTempPreviewing(player, isAlwaysShow());
|
||||
} else if (player.isLoaded() && player.isTempPreviewing()) {
|
||||
setTempPreviewing(player, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -51,7 +55,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
private final HashMap<String, Integer> refreshIntervals = new HashMap<>();
|
||||
private final HashMap<Integer, Integer> fasterRefreshIntervals = 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 HashMap<String, Placeholder> nestedPlaceholders = new HashMap<>();
|
||||
@@ -201,7 +205,7 @@ 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++) {
|
||||
@@ -209,7 +213,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
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()));
|
||||
@@ -575,15 +579,15 @@ 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<RelationalPlaceholder> delayedPlaceholdersToUpdate = new ArrayList<>();
|
||||
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) {
|
||||
TimeStampData<String> previous = player.getValue(placeholder);
|
||||
TimeStampData<String> previous = player.getRawPlayerValue(playerPlaceholder);
|
||||
if (previous == null) {
|
||||
String value = playerPlaceholder.request(player);
|
||||
player.setValue(placeholder, new TimeStampData<>(value, MainTask.getTicks(), true));
|
||||
player.setPlayerValue(playerPlaceholder, new TimeStampData<>(value, MainTask.getTicks(), true));
|
||||
featuresToNotifyUpdates.addAll(player.activeFeatures(placeholder));
|
||||
} else {
|
||||
if (previous.ticks() > MainTask.getTicks() - getRefreshInterval(placeholder.countId())) {
|
||||
@@ -605,7 +609,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
} else if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
delayedPlaceholdersToUpdate.add(relationalPlaceholder);
|
||||
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
|
||||
TimeStampData<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
|
||||
@@ -614,7 +618,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
} else {
|
||||
value = sharedPlaceholder.request();
|
||||
}
|
||||
player.setValue(placeholder, new TimeStampData<>(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
|
||||
@@ -645,14 +649,14 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
|
||||
for (RelationalPlaceholder placeholder : delayedPlaceholdersToUpdate) {
|
||||
for (CNPlayer nearby : player.nearbyPlayers()) {
|
||||
TimeStampData<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 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);
|
||||
}
|
||||
}
|
||||
@@ -663,7 +667,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -677,7 +681,7 @@ public class PlaceholderManagerImpl implements PlaceholderManager {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -773,7 +777,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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
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;
|
||||
@@ -26,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;
|
||||
@@ -42,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();
|
||||
@@ -178,6 +202,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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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,8 +37,9 @@ public abstract class PlaceholdersRequirement extends AbstractRequirement {
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
p1.forceUpdatePlaceholders(t1.placeholders(), Set.of(p2));
|
||||
p1.forceUpdatePlaceholders(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);
|
||||
|
||||
@@ -66,7 +66,7 @@ other-settings:
|
||||
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: 1 # Set default condition refresh interval
|
||||
default-condition-refresh-interval: 20 # Set default condition refresh interval
|
||||
default-placeholder-refresh-interval: 1 # Set default placeholder refresh interval
|
||||
placeholder-refresh-interval: # Custom placeholder refresh intervals for performance optimization
|
||||
"%player_name%": 100
|
||||
@@ -167,13 +167,14 @@ other-settings:
|
||||
unicode:
|
||||
file: unicode_page_%02x.png # Default Unicode characters
|
||||
sizes: glyph_sizes.bin # Glyph size configuration
|
||||
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
|
||||
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
|
||||
|
||||
@@ -26,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_-179%%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'
|
||||
@@ -130,30 +146,31 @@ 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': "</WHITE>"
|
||||
'enter': "</WHITE>"
|
||||
world:
|
||||
switch: '%player_world%'
|
||||
case:
|
||||
|
||||
@@ -9,7 +9,20 @@ nameplate:
|
||||
player-name: '%np_shift_player_name%'
|
||||
suffix: '%np_switch_nameplate_color_suffix%'
|
||||
unlimited:
|
||||
tag_1:
|
||||
tag_normal:
|
||||
text: '%np_tag-text%'
|
||||
translation: 0,0.2,0
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
has-nameplate: false
|
||||
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
|
||||
tag_image_part:
|
||||
text: '%np_tag-image%'
|
||||
translation: 0,0.2,0
|
||||
viewer-conditions: { }
|
||||
@@ -22,7 +35,7 @@ unlimited:
|
||||
affected-by-spectator: true
|
||||
line-width: 1024
|
||||
background-color: 0,0,0,0
|
||||
tag_2:
|
||||
tag_text_part:
|
||||
text: '%np_tag-text%'
|
||||
translation: 0.01,0.2,0.01
|
||||
viewer-conditions: { }
|
||||
@@ -34,17 +47,4 @@ unlimited:
|
||||
affected-by-scale-attribute: true
|
||||
affected-by-spectator: true
|
||||
line-width: 1024
|
||||
background-color: 0,0,0,0
|
||||
tag_3:
|
||||
text: '%np_tag-text%'
|
||||
translation: 0,0.2,0
|
||||
viewer-conditions: { }
|
||||
owner-conditions:
|
||||
has-nameplate: false
|
||||
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: 0,0,0,0
|
||||
@@ -1,3 +1,4 @@
|
||||
image: bell
|
||||
height: 10
|
||||
ascent: 4
|
||||
ascent: 4
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: bubble
|
||||
height: 10
|
||||
ascent: 4
|
||||
ascent: 4
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: clock
|
||||
height: 10
|
||||
ascent: 4
|
||||
ascent: 4
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: coin
|
||||
height: 10
|
||||
ascent: -14
|
||||
ascent: -14
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: compass
|
||||
height: 10
|
||||
ascent: 4
|
||||
ascent: 4
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: stamina_0
|
||||
height: 9
|
||||
ascent: -16
|
||||
ascent: -16
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: stamina_1
|
||||
height: 9
|
||||
ascent: -16
|
||||
ascent: -16
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: stamina_2
|
||||
height: 9
|
||||
ascent: -16
|
||||
ascent: -16
|
||||
shadow: false
|
||||
@@ -1,3 +1,4 @@
|
||||
image: weather
|
||||
height: 10
|
||||
ascent: 4
|
||||
ascent: 4
|
||||
shadow: false
|
||||
@@ -0,0 +1,13 @@
|
||||
display-name: Angel
|
||||
left:
|
||||
image: angel_left
|
||||
height: 16
|
||||
ascent: 14
|
||||
middle:
|
||||
image: angel_middle
|
||||
height: 16
|
||||
ascent: 14
|
||||
right:
|
||||
image: angel_right
|
||||
height: 16
|
||||
ascent: 14
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1006 B |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,13 @@
|
||||
display-name: Banner
|
||||
left:
|
||||
image: banner_left
|
||||
height: 16
|
||||
ascent: 13
|
||||
middle:
|
||||
image: banner_middle
|
||||
height: 16
|
||||
ascent: 13
|
||||
right:
|
||||
image: banner_right
|
||||
height: 16
|
||||
ascent: 13
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1000 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 396 B |
|
Before Width: | Height: | Size: 194 B |
|
Before Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,13 +1,13 @@
|
||||
display-name: Sad Cat
|
||||
display-name: Enter
|
||||
left:
|
||||
image: cat_left
|
||||
image: enter_left
|
||||
height: 16
|
||||
ascent: 12
|
||||
middle:
|
||||
image: cat_middle
|
||||
image: enter_middle
|
||||
height: 16
|
||||
ascent: 12
|
||||
right:
|
||||
image: cat_right
|
||||
image: enter_right
|
||||
height: 16
|
||||
ascent: 12
|
||||
|
After Width: | Height: | Size: 957 B |
|
After Width: | Height: | Size: 958 B |
|
After Width: | Height: | Size: 1.0 KiB |
@@ -1,13 +1,13 @@
|
||||
display-name: Thank you, Cheems
|
||||
display-name: Video Game Console
|
||||
left:
|
||||
image: cheems_left
|
||||
image: game_left
|
||||
height: 16
|
||||
ascent: 12
|
||||
middle:
|
||||
image: cheems_middle
|
||||
image: game_middle
|
||||
height: 16
|
||||
ascent: 12
|
||||
right:
|
||||
image: cheems_right
|
||||
image: game_right
|
||||
height: 16
|
||||
ascent: 12
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 958 B |
|
After Width: | Height: | Size: 1.0 KiB |
@@ -1,13 +1,13 @@
|
||||
display-name: Wither Rose
|
||||
display-name: Panda
|
||||
left:
|
||||
image: wither_left
|
||||
image: panda_left
|
||||
height: 16
|
||||
ascent: 12
|
||||
middle:
|
||||
image: wither_middle
|
||||
image: panda_middle
|
||||
height: 16
|
||||
ascent: 12
|
||||
right:
|
||||
image: wither_right
|
||||
image: panda_right
|
||||
height: 16
|
||||
ascent: 12
|
||||
|
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 997 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1015 B |
|
Before Width: | Height: | Size: 928 B After Width: | Height: | Size: 999 B |
@@ -0,0 +1,13 @@
|
||||
display-name: Oak Sign
|
||||
left:
|
||||
image: sign_left
|
||||
height: 16
|
||||
ascent: 14
|
||||
middle:
|
||||
image: sign_middle
|
||||
height: 16
|
||||
ascent: 14
|
||||
right:
|
||||
image: sign_right
|
||||
height: 16
|
||||
ascent: 14
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1023 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -52,6 +52,11 @@ public class BukkitCNPlayer extends AbstractCNPlayer {
|
||||
this.player = new WeakReference<>(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return player != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player player() {
|
||||
return player.get();
|
||||
|
||||
@@ -63,7 +63,7 @@ public class BukkitChatManager extends AbstractChatManager {
|
||||
}
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("Oraxen")) {
|
||||
try {
|
||||
this.emojiProviders.add(new OraxenEmojiProvider());
|
||||
this.emojiProviders.add(new OraxenEmojiProvider(Bukkit.getPluginManager().getPlugin("Oraxen").getDescription().getVersion().startsWith("1") ? 1 : 2));
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import net.momirealms.customnameplates.bukkit.command.BukkitCommandManager;
|
||||
import net.momirealms.customnameplates.bukkit.compatibility.NameplatesExpansion;
|
||||
import net.momirealms.customnameplates.bukkit.compatibility.NameplatesExtraExpansion;
|
||||
import net.momirealms.customnameplates.bukkit.compatibility.cosmetic.MagicCosmeticsHook;
|
||||
import net.momirealms.customnameplates.bukkit.compatibility.region.WorldGuardRegion;
|
||||
import net.momirealms.customnameplates.bukkit.requirement.BukkitRequirementManager;
|
||||
import net.momirealms.customnameplates.bukkit.scheduler.BukkitSchedulerAdapter;
|
||||
import net.momirealms.customnameplates.bukkit.util.SimpleLocation;
|
||||
@@ -204,6 +205,12 @@ public class BukkitCustomNameplates extends CustomNameplates implements Listener
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) {
|
||||
try {
|
||||
WorldGuardRegion.register();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
boolean downloadFromPolymart = polymart.equals("1");
|
||||
boolean downloadFromBBB = buildByBit.equals("true");
|
||||
@@ -302,6 +309,8 @@ public class BukkitCustomNameplates extends CustomNameplates implements Listener
|
||||
for (CNPlayer player : getOnlinePlayers()) {
|
||||
((AbstractCNPlayer) player).reload();
|
||||
}
|
||||
// clear requirement ids
|
||||
this.requirementManager.reload();
|
||||
// load basics
|
||||
this.configManager.reload();
|
||||
this.storageManager.reload();
|
||||
@@ -314,8 +323,6 @@ public class BukkitCustomNameplates extends CustomNameplates implements Listener
|
||||
this.advanceManager.reload();
|
||||
// set up placeholders
|
||||
this.placeholderManager.reload();
|
||||
// set up requirements
|
||||
this.requirementManager.reload();
|
||||
// use the placeholders
|
||||
this.actionBarManager.reload();
|
||||
this.bossBarManager.reload();
|
||||
|
||||
@@ -204,22 +204,62 @@ public class BukkitPlatform implements Platform {
|
||||
}
|
||||
}, "PacketPlayOutEntityDestroy", "ClientboundRemoveEntitiesPacket");
|
||||
|
||||
// for skin plugin compatibility
|
||||
registerPacketConsumer((player, event, packet) -> {
|
||||
try {
|
||||
if (!player.isInitialized()) return;
|
||||
UUID pUUID = player.uuid();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<UUID> uuids = (List<UUID>) Reflections.field$ClientboundPlayerInfoRemovePacket$profileIds.get(packet);
|
||||
for (UUID uuid : uuids) {
|
||||
if (uuid.equals(pUUID)) {
|
||||
CNPlayer removed = CustomNameplates.getInstance().getPlayer(uuid);
|
||||
if (removed != null) {
|
||||
removed.removePlayerFromTracker(player);
|
||||
CustomNameplates.getInstance().getUnlimitedTagManager().onRemovePlayer(removed, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CustomNameplates.getInstance().getPluginLogger().severe("Failed to handle ClientboundPlayerInfoRemovePacket", e);
|
||||
}
|
||||
}, "ClientboundPlayerInfoRemovePacket");
|
||||
|
||||
registerPacketConsumer((player, event, packet) -> {
|
||||
try {
|
||||
EnumSet<?> enums = (EnumSet<?>) Reflections.field$ClientboundPlayerInfoUpdatePacket$actions.get(packet);
|
||||
if (enums == null) return;
|
||||
if (!enums.contains(Reflections.enum$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_GAME_MODE)) return;
|
||||
List<Object> entries = (List<Object>) Reflections.field$ClientboundPlayerInfoUpdatePacket$entries.get(packet);
|
||||
for (Object entry : entries) {
|
||||
UUID uuid = (UUID) Reflections.field$ClientboundPlayerInfoUpdatePacket$Entry$profileId.get(entry);
|
||||
if (uuid == null) continue;
|
||||
Object gameType = Reflections.field$ClientboundPlayerInfoUpdatePacket$Entry$gameMode.get(entry);
|
||||
if (gameType == null) continue;
|
||||
int mode = (int) Reflections.method$GameType$getId.invoke(gameType);
|
||||
boolean isSpectator = mode == 3;
|
||||
CNPlayer another = CustomNameplates.getInstance().getPlayer(uuid);
|
||||
if (another != null) {
|
||||
CustomNameplates.getInstance().getUnlimitedTagManager().onPlayerGameModeChange(another, player, isSpectator);
|
||||
boolean add_player = enums.contains(Reflections.enum$ClientboundPlayerInfoUpdatePacket$Action$ADD_PLAYER);
|
||||
boolean update_gamemode = enums.contains(Reflections.enum$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_GAME_MODE);
|
||||
if (add_player || update_gamemode) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> entries = (List<Object>) Reflections.field$ClientboundPlayerInfoUpdatePacket$entries.get(packet);
|
||||
for (Object entry : entries) {
|
||||
UUID uuid = (UUID) Reflections.field$ClientboundPlayerInfoUpdatePacket$Entry$profileId.get(entry);
|
||||
if (uuid == null) continue;
|
||||
|
||||
// for skin plugin compatibility
|
||||
if (add_player && player.isInitialized()) {
|
||||
UUID pUUID = player.uuid();
|
||||
if (uuid.equals(pUUID) && (player.isTempPreviewing() || player.isToggleablePreviewing() || CustomNameplates.getInstance().getUnlimitedTagManager().isAlwaysShow())) {
|
||||
Tracker tracker = player.addPlayerToTracker(player);
|
||||
tracker.setScale(player.scale());
|
||||
tracker.setCrouching(player.isCrouching());
|
||||
tracker.setSpectator(player.isSpectator());
|
||||
CustomNameplates.getInstance().getUnlimitedTagManager().onAddPlayer(player, player);
|
||||
}
|
||||
}
|
||||
|
||||
CNPlayer another = CustomNameplates.getInstance().getPlayer(uuid);
|
||||
if (update_gamemode) {
|
||||
Object gameType = Reflections.field$ClientboundPlayerInfoUpdatePacket$Entry$gameMode.get(entry);
|
||||
if (gameType == null) continue;
|
||||
int mode = (int) Reflections.method$GameType$getId.invoke(gameType);
|
||||
boolean isSpectator = mode == 3;
|
||||
if (another != null) {
|
||||
CustomNameplates.getInstance().getUnlimitedTagManager().onPlayerGameModeChange(another, player, isSpectator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package net.momirealms.customnameplates.bukkit.command.feature;
|
||||
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.JoinQuitListener;
|
||||
import net.momirealms.customnameplates.bukkit.BukkitCustomNameplates;
|
||||
import net.momirealms.customnameplates.bukkit.command.BukkitCommandFeature;
|
||||
@@ -45,6 +46,7 @@ public class NameplatesPreviewCommand extends BukkitCommandFeature<CommandSender
|
||||
.senderType(Player.class)
|
||||
.handler(context -> {
|
||||
if (!ConfigManager.nametagModule()) return;
|
||||
if (CustomNameplates.getInstance().getUnlimitedTagManager().isAlwaysShow()) return;
|
||||
CNPlayer player = plugin.getPlayer(context.sender().getUniqueId());
|
||||
if (player == null) {
|
||||
throw new RuntimeException("Player should not be null");
|
||||
|
||||
@@ -52,6 +52,14 @@ public class BukkitRequirementManager extends AbstractRequirementManager {
|
||||
this.registerGameMode();
|
||||
this.registerBedrock();
|
||||
this.registerDisguise();
|
||||
this.registerPassenger();
|
||||
}
|
||||
|
||||
private void registerPassenger() {
|
||||
this.registerRequirement((args, interval) -> {
|
||||
boolean is = (boolean) args;
|
||||
return new PassengerRequirement(interval, is);
|
||||
}, "is-passenger");
|
||||
}
|
||||
|
||||
private void registerDisguise() {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.bukkit.requirement.builtin;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PassengerRequirement extends AbstractRequirement {
|
||||
|
||||
private final boolean is;
|
||||
|
||||
public PassengerRequirement(int refreshInterval, boolean is) {
|
||||
super(refreshInterval);
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||
return ((Player) p1.player()).isInsideVehicle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "is-passenger";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof PassengerRequirement that)) return false;
|
||||
return is == that.is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(is);
|
||||
}
|
||||
}
|
||||
@@ -429,6 +429,18 @@ public class Reflections {
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ClientboundPlayerInfoRemovePacket = requireNonNull(
|
||||
ReflectionUtils.getClazz(
|
||||
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundPlayerInfoRemovePacket")
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$ClientboundPlayerInfoRemovePacket$profileIds = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(
|
||||
clazz$ClientboundPlayerInfoRemovePacket, 0
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$ClientboundRemoveEntitiesPacket$entityIds = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(
|
||||
clazz$ClientboundRemoveEntitiesPacket, 0
|
||||
@@ -819,7 +831,7 @@ public class Reflections {
|
||||
);
|
||||
|
||||
public static final Enum<?> enum$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_GAME_MODE;
|
||||
|
||||
public static final Enum<?> enum$ClientboundPlayerInfoUpdatePacket$Action$ADD_PLAYER;
|
||||
|
||||
static {
|
||||
Enum<?> updateGameMode;
|
||||
@@ -829,6 +841,14 @@ public class Reflections {
|
||||
updateGameMode = Enum.valueOf((Class<Enum>) clazz$ClientboundPlayerInfoUpdatePacket$Action, "c");
|
||||
}
|
||||
enum$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_GAME_MODE = updateGameMode;
|
||||
|
||||
Enum<?> addPlayer;
|
||||
try {
|
||||
addPlayer = Enum.valueOf((Class<Enum>) clazz$ClientboundPlayerInfoUpdatePacket$Action, "ADD_PLAYER");
|
||||
} catch (Exception e) {
|
||||
addPlayer = Enum.valueOf((Class<Enum>) clazz$ClientboundPlayerInfoUpdatePacket$Action, "a");
|
||||
}
|
||||
enum$ClientboundPlayerInfoUpdatePacket$Action$ADD_PLAYER = addPlayer;
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$ClientboundPlayerInfoUpdatePacket$Entry = requireNonNull(
|
||||
|
||||
@@ -15,6 +15,7 @@ softdepend:
|
||||
- AdvancedChat
|
||||
- VentureChat
|
||||
- EssentialsChat
|
||||
- WorldGuard
|
||||
permissions:
|
||||
nameplates.command.equip:
|
||||
default: true
|
||||
|
||||
@@ -11,11 +11,16 @@ repositories {
|
||||
maven("https://repo.essentialsx.net/releases/") // ess
|
||||
maven("https://repo.md-5.net/content/groups/public/") // disguise
|
||||
maven("https://repo.opencollab.dev/main/") // geyser
|
||||
maven("https://maven.enginehub.org/repo/") // worldguard worldedit
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":api"))
|
||||
compileOnly(project(":common"))
|
||||
compileOnly(project(":backend"))
|
||||
compileOnly("dev.dejvokep:boosted-yaml:${rootProject.properties["boosted_yaml_version"]}")
|
||||
// WorldGuard
|
||||
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9")
|
||||
// Platform
|
||||
compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT")
|
||||
// Chat
|
||||
|
||||
@@ -21,18 +21,15 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import me.clip.placeholderapi.expansion.Relational;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
import net.momirealms.customnameplates.api.feature.TimeStampData;
|
||||
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 org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class NameplatesExpansion extends PlaceholderExpansion implements Relational {
|
||||
|
||||
private final CustomNameplates plugin;
|
||||
@@ -64,14 +61,10 @@ public class NameplatesExpansion extends PlaceholderExpansion implements Relatio
|
||||
@Override
|
||||
public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
|
||||
Placeholder placeholder = plugin.getPlaceholderManager().getRegisteredPlaceholder("%np_" + params + "%");
|
||||
CNPlayer cnPlayer = player == null ? null : plugin.getPlayer(player.getUniqueId());
|
||||
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
|
||||
CNPlayer cnPlayer = player == null ? null : plugin.getPlayer(player.getUniqueId());
|
||||
if (placeholder.children().isEmpty()) {
|
||||
return playerPlaceholder.request(cnPlayer);
|
||||
}
|
||||
if (cnPlayer != null) {
|
||||
cnPlayer.forceUpdatePlaceholders(Set.of(placeholder), Collections.emptySet());
|
||||
return cnPlayer.getData(placeholder);
|
||||
return cnPlayer.getCachedPlayerValue(playerPlaceholder);
|
||||
} else {
|
||||
try {
|
||||
return playerPlaceholder.request(null);
|
||||
@@ -79,6 +72,12 @@ public class NameplatesExpansion extends PlaceholderExpansion implements Relatio
|
||||
plugin.getPluginLogger().warn("%nameplates_" + params + "% contains a placeholder that requires a player as the parameter");
|
||||
}
|
||||
}
|
||||
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
|
||||
if (cnPlayer != null) {
|
||||
return cnPlayer.getCachedSharedValue(sharedPlaceholder);
|
||||
} else {
|
||||
return sharedPlaceholder.request();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -91,9 +90,8 @@ public class NameplatesExpansion extends PlaceholderExpansion implements Relatio
|
||||
return null;
|
||||
}
|
||||
Placeholder placeholder = plugin.getPlaceholderManager().getRegisteredPlaceholder("%rel_np_" + params + "%");
|
||||
if (placeholder != null) {
|
||||
cnPlayer1.forceUpdatePlaceholders(Set.of(placeholder), Set.of(cnPlayer2));
|
||||
return Optional.ofNullable(cnPlayer1.getRelationalValue(placeholder, cnPlayer2)).map(TimeStampData::data).orElse(placeholder.id());
|
||||
if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
|
||||
return cnPlayer1.getCachedRelationalValue(relationalPlaceholder, cnPlayer2);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,9 @@ public class NameplatesExtraExpansion extends PlaceholderExpansion {
|
||||
String minuteStr = (minutes < 10) ? "0" + minutes : String.valueOf(minutes);
|
||||
return hours + ":" + minuteStr;
|
||||
}
|
||||
case "newline" -> {
|
||||
return "\n";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||