9
0
mirror of https://github.com/Xiao-MoMi/Custom-Nameplates.git synced 2025-12-19 15:09:23 +00:00
This commit is contained in:
XiaoMoMi
2024-01-18 02:01:28 +08:00
parent 824879d611
commit 22c5af10e3
624 changed files with 12741 additions and 18497 deletions

145
.gitignore vendored
View File

@@ -1,117 +1,42 @@
# User-specific stuff
.idea/
*.iml
*.ipr
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
# Ignore Gradle GUI config
gradle-app.setting
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
# Cache of project
.gradletasknamecache
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
**/build/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
# Common working directory
run/
### VS Code ###
.vscode/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
### Mac OS ###
.DS_Store

42
api/.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

4
api/build.gradle.kts Normal file
View File

@@ -0,0 +1,4 @@
dependencies {
compileOnly("dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
}

View File

@@ -0,0 +1,112 @@
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.manager.*;
import net.momirealms.customnameplates.api.scheduler.Scheduler;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
public abstract class CustomNameplatesPlugin extends JavaPlugin {
protected static CustomNameplatesPlugin instance;
protected Scheduler scheduler;
protected StorageManager storageManager;
protected VersionManager versionManager;
protected AdventureManager adventureManager;
protected RequirementManager requirementManager;
protected BossBarManager bossBarManager;
protected ImageManager imageManager;
protected PlaceholderManager placeholderManager;
protected ResourcePackManager resourcePackManager;
protected BackGroundManager backGroundManager;
protected TeamManager teamManager;
protected NameplateManager nameplateManager;
protected ActionBarManager actionBarManager;
protected CustomNameplatesPlugin() {
instance = this;
}
/* Get plugin instance */
public static CustomNameplatesPlugin getInstance() {
return instance;
}
/* Get plugin instance */
public static CustomNameplatesPlugin get() {
return instance;
}
/* reload the plugin */
public abstract void reload(boolean generatePack);
/* Get the scheduler */
public Scheduler getScheduler() {
return scheduler;
}
/* Get the storage manager */
public StorageManager getStorageManager() {
return storageManager;
}
/* Get the requirement manager */
public RequirementManager getRequirementManager() {
return requirementManager;
}
/* Get the image manager */
public ImageManager getImageManager() {
return imageManager;
}
/* Get the background manager */
public BackGroundManager getBackGroundManager() {
return backGroundManager;
}
/* Get the resource pack manager */
public ResourcePackManager getResourcePackManager() {
return resourcePackManager;
}
/* Get the adventure manager */
public AdventureManager getAdventure() {
return adventureManager;
}
/* Get the version manager */
public VersionManager getVersionManager() {
return versionManager;
}
/* Get the bossbar manager */
public BossBarManager getBossBarManager() {
return bossBarManager;
}
/* Get the placeholder manager */
public PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
/* Get the team manager */
public TeamManager getTeamManager() {
return teamManager;
}
/* Get the actionbar manager */
public ActionBarManager getActionBarManager() {
return actionBarManager;
}
/* Get the nameplate manager */
public NameplateManager getNameplateManager() {
return nameplateManager;
}
/* debug get config by file name */
public abstract YamlConfiguration getConfig(String file);
/* debug message */
public abstract void debug(String s);
}

View File

@@ -15,25 +15,32 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.object.scheduler;
package net.momirealms.customnameplates.api.common;
import org.bukkit.scheduler.BukkitTask;
public record Key(String namespace, String value) {
public class BukkitTimerTask implements TimerTask {
private final BukkitTask bukkitTask;
public BukkitTimerTask(BukkitTask bukkitTask) {
this.bukkitTask = bukkitTask;
public static Key of(String namespace, String value) {
return new Key(namespace, value);
}
@Override
public void cancel() {
bukkitTask.cancel();
public int hashCode() {
int result = this.namespace.hashCode();
result = (31 * result) + this.value.hashCode();
return result;
}
@Override
public boolean isCancelled() {
return bukkitTask.isCancelled();
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Key key)) return false;
return this.namespace.equals(key.namespace()) && this.value.equals(key.value());
}
@Override
public String toString() {
return namespace + ":" + value;
}
}

View File

@@ -15,14 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.object.placeholders;
package net.momirealms.customnameplates.api.common;
public record StaticText(String text, int value, StaticState staticState) {
public record Pair<L, R>(L left, R right) {
public enum StaticState {
LEFT,
MIDDLE,
RIGHT
public static <L, R> Pair<L, R> of(final L left, final R right) {
return new Pair<>(left, right);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.common;
import org.bukkit.Location;
import java.util.Objects;
public record SimpleLocation(String worldName, int x, int y, int z) {
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SimpleLocation other = (SimpleLocation) obj;
if (!Objects.equals(worldName, other.worldName())) {
return false;
}
if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
return false;
}
if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) {
return false;
}
if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 19 * hash + (worldName != null ? worldName.hashCode() : 0);
hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
return hash;
}
public static SimpleLocation getByBukkitLocation(Location location) {
return new SimpleLocation(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.common;
public class Tuple<L, M, R> {
private L left;
private M mid;
private R right;
public Tuple(L left, M mid, R right) {
this.left = left;
this.mid = mid;
this.right = right;
}
public static <L, M, R> Tuple<L, M, R> of(final L left, final M mid, final R right) {
return new Tuple<>(left, mid, right);
}
public L getLeft() {
return left;
}
public void setLeft(L left) {
this.left = left;
}
public M getMid() {
return mid;
}
public void setMid(M mid) {
this.mid = mid;
}
public R getRight() {
return right;
}
public void setRight(R right) {
this.right = right;
}
}

View File

@@ -0,0 +1,79 @@
package net.momirealms.customnameplates.api.data;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import org.bukkit.entity.Player;
import java.util.UUID;
public class OnlineUser {
private final Player player;
private String nameplate;
private String bubble;
public OnlineUser(Player player, PlayerData playerData) {
this.player = player;
this.nameplate = playerData.getNameplate();
this.bubble = playerData.getBubble();
}
public PlayerData toPlayerData() {
return PlayerData.builder()
.setBubble(bubble)
.setNameplate(nameplate)
.build();
}
public UUID getUUID() {
return player.getUniqueId();
}
public Player getPlayer() {
return player;
}
/**
* Get the original nameplate key from data
*/
public String getNameplateKey() {
return nameplate;
}
/**
* Get the original bubble key from data
*/
public String getBubbleKey() {
return bubble;
}
/**
* This value might be inconsistent with the key get by "getNameplateKey()"
* Because if a player doesn't have a nameplate, his nameplate would be the default one
*/
public Nameplate getNameplate() {
String temp = nameplate;
if (temp.equals("none")) {
temp = CustomNameplatesPlugin.get().getNameplateManager().getDefaultNameplate();
}
return CustomNameplatesPlugin.get().getNameplateManager().getNameplate(temp);
}
/**
* Set nameplate for a player
*
* @param nameplate nameplate
*/
public void setNameplate(String nameplate) {
this.nameplate = nameplate;
}
/**
* Set bubble for a player
*
* @param bubble bubble
*/
public void setBubble(String bubble) {
this.bubble = bubble;
}
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.customnameplates.api.data;
import com.google.gson.annotations.SerializedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerData {
@SerializedName("nameplate")
private String nameplate;
@SerializedName("bubble")
private String bubble;
public static Builder builder() {
return new Builder();
}
public static PlayerData empty() {
return new PlayerData.Builder()
.setNameplate("none")
.setBubble("none")
.build();
}
public String getNameplate() {
return nameplate;
}
public String getBubble() {
return bubble;
}
public static class Builder {
private final PlayerData playerData;
public Builder() {
this.playerData = new PlayerData();
}
@NotNull
public Builder setNameplate(@Nullable String nameplate) {
this.playerData.nameplate = nameplate;
return this;
}
@NotNull
public Builder setBubble(@Nullable String bubble) {
this.playerData.bubble = bubble;
return this;
}
@NotNull
public PlayerData build() {
return this.playerData;
}
}
}

View File

@@ -0,0 +1,30 @@
package net.momirealms.customnameplates.api.event;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class CustomNameplatesReloadEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final CustomNameplatesPlugin plugin;
public CustomNameplatesReloadEvent(CustomNameplatesPlugin plugin) {
this.plugin = plugin;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
public CustomNameplatesPlugin getPlugin() {
return plugin;
}
}

View File

@@ -0,0 +1,39 @@
package net.momirealms.customnameplates.api.event;
import net.momirealms.customnameplates.api.data.OnlineUser;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class NameplateDataLoadEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final UUID uuid;
private final OnlineUser onlineUser;
public NameplateDataLoadEvent(UUID uuid, OnlineUser onlineUser) {
super(true);
this.uuid = uuid;
this.onlineUser = onlineUser;
}
public UUID getUUID() {
return uuid;
}
public OnlineUser getOnlineUser() {
return onlineUser;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@@ -0,0 +1,43 @@
package net.momirealms.customnameplates.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerEquipBubbleEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private final String bubble;
private boolean isCancelled;
public PlayerEquipBubbleEvent(@NotNull Player who, String bubble) {
super(who);
this.bubble = bubble;
this.isCancelled = false;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlerList;
}
public static HandlerList getHandlerList() {
return handlerList;
}
public String getBubble() {
return bubble;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
}

View File

@@ -0,0 +1,43 @@
package net.momirealms.customnameplates.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerEquipNameplateEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private final String nameplate;
private boolean isCancelled;
public PlayerEquipNameplateEvent(@NotNull Player who, String nameplate) {
super(who);
this.nameplate = nameplate;
this.isCancelled = false;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlerList;
}
public static HandlerList getHandlerList() {
return handlerList;
}
public String getNameplate() {
return nameplate;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
}

View File

@@ -0,0 +1,37 @@
package net.momirealms.customnameplates.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerUnequipBubbleEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private boolean isCancelled;
public PlayerUnequipBubbleEvent(@NotNull Player who) {
super(who);
this.isCancelled = false;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlerList;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
}

View File

@@ -0,0 +1,37 @@
package net.momirealms.customnameplates.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerUnequipNameplateEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private boolean isCancelled;
public PlayerUnequipNameplateEvent(@NotNull Player who) {
super(who);
this.isCancelled = false;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlerList;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
}

View File

@@ -0,0 +1,17 @@
package net.momirealms.customnameplates.api.manager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public interface ActionBarManager {
/**
* Get the actionbar sent by other plugins in MiniMessage format
* Return "" if no other actionbar received
*
* @param player receiver
* @return text
*/
@NotNull
String getOtherPluginActionBar(Player player);
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public interface AdventureManager {
Object getIChatComponentFromMiniMessage(String text);
/**
* Strip all the tags from text
*
* @param text text
* @return stripped
*/
String stripTags(String text);
/**
* Get component from text
*
* @param text text
* @return component
*/
Component getComponentFromMiniMessage(String text);
/**
* Send a message to a command sender
*
* @param sender sender
* @param msg message
*/
void sendMessage(CommandSender sender, String msg);
/**
* Send a message with prefix to a command sender
*
* @param sender sender
* @param msg message
*/
void sendMessageWithPrefix(CommandSender sender, String msg);
/**
* Send a message to console
*
* @param msg message
*/
void sendConsoleMessage(String msg);
/**
* Send a message to a player
*
* @param player player
* @param msg message
*/
void sendPlayerMessage(Player player, String msg);
/**
* Send a title
*
* @param player player
* @param title title
* @param subtitle subtitle
* @param in in (ms)
* @param duration duration (ms)
* @param out out (ms)
*/
void sendTitle(Player player, String title, String subtitle, int in, int duration, int out);
/**
* Send a title
*
* @param player player
* @param title title
* @param subtitle subtitle
* @param in in (ms)
* @param duration duration (ms)
* @param out out (ms)
*/
void sendTitle(Player player, Component title, Component subtitle, int in, int duration, int out);
/**
* Send an actionbar
*
* @param player player
* @param msg msg
*/
void sendActionbar(Player player, String msg);
/**
* Send an actionbar
*
* @param player player
* @param component component
*/
void sendActionbar(Player player, Component component);
/**
* Play a sound to a player
*
* @param player player
* @param source sound source
* @param key sound key
* @param volume volume
* @param pitch pitch
*/
void sendSound(Player player, Sound.Source source, Key key, float volume, float pitch);
/**
* Play a sound to a player
*
* @param player player
* @param sound sound
*/
void sendSound(Player player, Sound sound);
/**
* Replace legacy color codes to MiniMessage format
*
* @param legacy legacy text
* @return MiniMessage format text
*/
String legacyToMiniMessage(String legacy);
/**
* If a char is legacy color code
*
* @param c char
* @return is legacy color
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isColorCode(char c);
/**
* Get legacy format text
*
* @param component component
* @return legacy format text
*/
String componentToLegacy(Component component);
/**
* Get json by component
*
* @param component component
* @return json
*/
String componentToJson(Component component);
/**
* Get the component in original package
*
* @param component shaded component
* @return paper component
*/
Object shadedToOriginal(Component component);
/**
* Get MiniMessage format text from component
*
* @param component component
* @return text
*/
String getMiniMessageFormat(Component component);
Object getIChatComponent(String json);
}

View File

@@ -0,0 +1,40 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.background.BackGround;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface BackGroundManager {
/**
* Get a background's config by key
*
* @param key key
* @return background
*/
@Nullable
BackGround getBackGround(@NotNull String key);
Collection<BackGround> getBackGrounds();
/**
* Register a background into the plugin
* This will fail if there already exists one with the same key
*
* @param key key
* @param backGround background
* @return success or not
*/
boolean registerBackGround(@NotNull String key, @NotNull BackGround backGround);
/**
* Unregister a background by key
* This will fail if the key doesn't exist
*
* @param key key
* @return success or not
*/
boolean unregisterBackGround(@NotNull String key);
}

View File

@@ -0,0 +1,5 @@
package net.momirealms.customnameplates.api.manager;
public interface BossBarManager {
}

View File

@@ -0,0 +1,40 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface ImageManager {
/**
* Get an image by key
*
* @param key key
* @return image
*/
@Nullable
ConfiguredChar getImage(@NotNull String key);
Collection<ConfiguredChar> getImages();
/**
* Register am image into the plugin
* This will fail if there already exists one with the same key
*
* @param key key
* @param configuredChar image
* @return success or not
*/
boolean registerImage(@NotNull String key, @NotNull ConfiguredChar configuredChar);
/**
* Unregister an image by key
* This will fail if the key doesn't exist
*
* @param key key
* @return success or not
*/
boolean unregisterImage(@NotNull String key);
}

View File

@@ -0,0 +1,158 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.nameplate.CachedNameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.TagMode;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.api.mechanic.team.TeamColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
public interface NameplateManager {
/**
* Get the default nameplate
*/
@NotNull
String getDefaultNameplate();
/**
* Put an entity's ID to map
* This map is used for quickly getting the entity instance
* Removal from the map is necessary when the entity is invalid
* Otherwise it would cause memory leak
*
* @param entityID entityID
* @param entity entity
*/
boolean putEntityIDToMap(int entityID, Entity entity);
/**
* Remove the entity from map
*
* @param entityID entityID
* @return the removed entity
*/
@Nullable
Entity removeEntityIDFromMap(int entityID);
/**
* Nameplates are cached in memory so they would not be frequently updated
* The update rate is decided by "refresh-frequency" in nameplate.yml
*
* @param uuid player uuid
* @param nameplate cached nameplate
*/
boolean putCachedNameplateToMap(UUID uuid, CachedNameplate nameplate);
/**
* Remove CachedNameplate from map
*
* @param uuid player uuid
* @return removed CachedNameplate
*/
@Nullable
CachedNameplate removeCachedNameplateFromMap(UUID uuid);
/**
* Get player by entityID from the cache
*
* @param id entityID
* @return player
*/
@Nullable
Player getPlayerByEntityID(int id);
/**
* Get entity by entityID from the cache
*
* @param id entityID
* @return entity
*/
@Nullable
Entity getEntityByEntityID(int id);
/**
* Update a player's cached nameplate
* The nameplate is affected by "prefix" and "suffix" option
*
* @param player player
* @return if the nameplate is updated
*/
boolean updateCachedNameplate(Player player);
/**
* Update a player's cached nameplate
* The nameplate is affected by "prefix" and "suffix" option
*
* @param player player
* @return if the nameplate is updated
*/
boolean updateCachedNameplate(Player player, Nameplate nameplate);
/**
* This should not be null when player's data is loaded (async process)
*
* @param player player
* @return cached nameplate
*/
@Nullable
CachedNameplate getCacheNameplate(Player player);
/**
* Create a name tag for a player, the tag type is decided by the mode in nameplate.yml
*
* @param player player
*/
void createNameTag(Player player);
void putNameplatePlayerToMap(NameplatePlayer player);
NameplatePlayer removeNameplatePlayerFromMap(UUID uuid);
String getNameplatePrefix(Player player);
String getNameplateSuffix(Player player);
String getFullNameTag(Player player);
boolean registerNameplate(String key, Nameplate nameplate);
void unEquipNameplate(Player player);
boolean unregisterNameplate(String key);
boolean isProxyMode();
TagMode getTagMode();
Nameplate getNameplate(String key);
Collection<Nameplate> getNameplates();
boolean containsNameplate(String key);
List<String> getAvailableNameplates(Player player);
/**
* If player has permission for a certain nameplate
*/
boolean hasNameplate(Player player, String nameplate);
/**
* Return false if nameplate doesn't exist
*/
boolean equipNameplate(Player player, String nameplate);
TeamColor getTeamColor(Player player);
TeamTagManager getTeamTagManager();
UnlimitedTagManager getUnlimitedTagManager();
}

View File

@@ -0,0 +1,73 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.placeholder.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface PlaceholderManager {
/**
* Detect all the placeholders
*
* @param text text
* @return placeholder
*/
@NotNull
List<String> detectPlaceholders(String text);
/**
* Get a static text instance
*
* @param key key
* @return static text
*/
@Nullable
StaticText getStaticText(String key);
/**
* Get a switch text instance
*
* @param key key
* @return switch text
*/
@Nullable
SwitchText getSwitchText(String key);
/**
* Get a descent text instance
*
* @param key key
* @return descent text
*/
@Nullable
DescentText getDescentText(String key);
/**
* Get a conditional text
*
* @param key key
* @return conditional text
*/
@Nullable
ConditionalText getConditionalText(String key);
/**
* Get a nameplate text
*
* @param key key
* @return nameplate text
*/
@Nullable
NameplateText getNameplateText(String key);
/**
* Get a background text
*
* @param key key
* @return background text
*/
@Nullable
BackGroundText getBackGroundText(String key);
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.requirement.RequirementFactory;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface RequirementManager {
/**
* Registers a custom requirement type with its corresponding factory.
*
* @param type The type identifier of the requirement.
* @param requirementFactory The factory responsible for creating instances of the requirement.
* @return True if registration was successful, false if the type is already registered.
*/
boolean registerRequirement(String type, RequirementFactory requirementFactory);
/**
* Unregisters a custom requirement type.
*
* @param type The type identifier of the requirement to unregister.
* @return True if unregistration was successful, false if the type is not registered.
*/
boolean unregisterRequirement(String type);
/**
* Retrieves an array of requirements based on a configuration section.
*
* @param section The configuration section containing requirement definitions.
* @return An array of Requirement objects based on the configuration section
*/
@Nullable Requirement[] getRequirements(ConfigurationSection section);
/**
* Retrieves a Requirement object based on a configuration section and advanced flag.
* <p>
* requirement_1: <- section
* type: xxx
* value: xxx
*
* @param section The configuration section containing requirement definitions.
* @return A Requirement object based on the configuration section, or an EmptyRequirement if the section is null or invalid.
*/
@NotNull Requirement getRequirement(ConfigurationSection section);
/**
* Gets a requirement based on the provided type and value.
* If a valid RequirementFactory is found for the type, it is used to create the requirement.
* If no factory is found, a warning is logged, and an empty requirement instance is returned.
* <p>
* world: <- type
* - world <- value
*
* @param type The type representing the requirement type.
* @param value The value associated with the requirement.
* @return A Requirement instance based on the type and value, or an EmptyRequirement if the type is invalid.
*/
@NotNull Requirement getRequirement(String type, Object value);
/**
* Retrieves a RequirementFactory based on the specified requirement type.
*
* @param type The requirement type for which to retrieve a factory.
* @return A RequirementFactory for the specified type, or null if no factory is found.
*/
@Nullable RequirementFactory getRequirementFactory(String type);
/**
* Checks if an array of requirements is met for a given condition.
*
* @param condition The Condition object to check against the requirements.
* @param requirements An array of Requirement instances to be evaluated.
* @return True if all requirements are met, false otherwise. Returns true if the requirements array is null.
*/
static boolean isRequirementMet(Condition condition, Requirement... requirements) {
if (requirements == null) return true;
for (Requirement requirement : requirements) {
if (!requirement.isConditionMet(condition)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,15 @@
package net.momirealms.customnameplates.api.manager;
import java.io.File;
public interface ResourcePackManager {
/**
* Generate the resource pack
*/
void generateResourcePack();
void deleteDirectory(File file);
String native2ascii(char c);
}

View File

@@ -0,0 +1,88 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.data.OnlineUser;
import net.momirealms.customnameplates.api.data.PlayerData;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface StorageManager {
/**
* Get online users
*
* @return online users
*/
Collection<OnlineUser> getOnlineUsers();
/**
* Get a player's data by uuid
* The player can be an offline one
*
* @param uuid uuid
* @return player data
*/
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid);
/**
* Save online players' data
*
* @param uuid uuid
* @return success or not
*/
CompletableFuture<Boolean> saveOnlinePlayerData(UUID uuid);
/**
* Save specified data
*
* @param uuid uuid
* @param playerData playerData
* @return success or not
*/
CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData);
/**
* Get an online user by uuid
*
* @param uuid uuid
* @return online user
*/
Optional<OnlineUser> getOnlineUser(UUID uuid);
/**
* Get player data from json
*
* @param json json
* @return data
*/
@NotNull
PlayerData fromJson(String json);
/**
* Get player data from bytes
*
* @param data data
* @return data
*/
PlayerData fromBytes(byte[] data);
/**
* Convert player data to bytes
*
* @param playerData playerData
* @return bytes
*/
byte[] toBytes(PlayerData playerData);
/**
* Convert player data to json
*
* @param playerData playerData
* @return json
*/
@NotNull
String toJson(@NotNull PlayerData playerData);
}

View File

@@ -0,0 +1,47 @@
package net.momirealms.customnameplates.api.manager;
import net.kyori.adventure.text.Component;
import net.momirealms.customnameplates.api.mechanic.team.TeamColor;
import net.momirealms.customnameplates.api.mechanic.team.TeamTagVisibility;
import org.bukkit.entity.Player;
public interface TeamManager {
/**
* Create team for a player
*
* @param player player
*/
void createTeam(Player player);
/**
* Create a team for a player on proxy
*
* @param player player
*/
void createProxyTeam(Player player);
/**
* Remove a team for a player
*
* @param player player
*/
void removeTeam(Player player);
/**
* Remove a team for a player on proxy
*
* @param player player
*/
void removeProxyTeam(Player player);
void updateTeam(Player owner, Player viewer, Component prefix, Component suffix, TeamColor color, TeamTagVisibility visibility);
/**
* Get the team player in
*
* @param player player
* @return team name
*/
String getTeamName(Player player);
}

View File

@@ -0,0 +1,29 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.tag.team.TeamPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public interface TeamTagManager {
/**
* Create team tag for a player
* If failed, the return value would be null
* This happens when there already exists a team tag for a player
*
* @return team tag
*/
@Nullable
TeamPlayer createTagForPlayer(Player player, String prefix, String suffix);
/**
* Remove a team tag from map by uuid
*
* @param uuid uuid
* @return team tag
*/
@Nullable
TeamPlayer removeTeamPlayerFromMap(UUID uuid);
}

View File

@@ -0,0 +1,56 @@
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.NamedEntity;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.UnlimitedObject;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.UnlimitedPlayer;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.UnlimitedTagSetting;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
public interface UnlimitedTagManager {
/**
* Create a named entity (ArmorStand) for a player
* To apply the changes, you should add it the named player instance
*
* @param player player
* @param setting setting
* @return named entity
*/
@NotNull
NamedEntity createNamedEntity(UnlimitedPlayer player, UnlimitedTagSetting setting);
/**
* Create unlimited tags for a player
* If failed, the return value would be null
* This happens when there already exists an UnlimitedObject for a player
*
* @param player player
* @param settings settings
* @return unlimited tag
*/
@Nullable
UnlimitedPlayer createTagForPlayer(Player player, List<UnlimitedTagSetting> settings);
/**
* Remove UnlimitedObject from map by uuid
*
* @param uuid uuid
* @return The removed unlimited object
*/
@Nullable
UnlimitedObject removeUnlimitedObjectFromMap(UUID uuid);
/**
* Get an UnlimitedObject from map by uuid
*
* @param uuid uuid
* @return The unlimited object
*/
@Nullable
UnlimitedObject getUnlimitedObject(UUID uuid);
}

View File

@@ -0,0 +1,26 @@
package net.momirealms.customnameplates.api.manager;
import java.util.concurrent.CompletionStage;
public interface VersionManager {
boolean isFolia();
String getServerVersion();
CompletionStage<Boolean> checkUpdate();
boolean isVersionNewerThan1_19_R2();
boolean isVersionNewerThan1_20();
boolean isVersionNewerThan1_20_R2();
String getPluginVersion();
boolean isLatest();
boolean isVersionNewerThan1_19();
int getPackFormat();
}

View File

@@ -0,0 +1,5 @@
package net.momirealms.customnameplates.api.manager;
public interface WidthManager {
}

View File

@@ -0,0 +1,212 @@
package net.momirealms.customnameplates.api.mechanic.background;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
public class BackGround {
private ConfiguredChar left, offset_1, offset_2, offset_4, offset_8, offset_16, offset_32, offset_64, offset_128, right;
private int leftMargin, rightMargin;
private BackGround() {
}
public BackGround(
ConfiguredChar left,
ConfiguredChar offset_1,
ConfiguredChar offset_2,
ConfiguredChar offset_4,
ConfiguredChar offset_8,
ConfiguredChar offset_16,
ConfiguredChar offset_32,
ConfiguredChar offset_64,
ConfiguredChar offset_128,
ConfiguredChar right,
int leftMargin,
int rightMargin
) {
this.left = left;
this.offset_1 = offset_1;
this.offset_2 = offset_2;
this.offset_4 = offset_4;
this.offset_8 = offset_8;
this.offset_16 = offset_16;
this.offset_32 = offset_32;
this.offset_64 = offset_64;
this.offset_128 = offset_128;
this.right = right;
this.leftMargin = leftMargin;
this.rightMargin = rightMargin;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getOffset_1() {
return offset_1;
}
public ConfiguredChar getOffset_2() {
return offset_2;
}
public ConfiguredChar getOffset_4() {
return offset_4;
}
public ConfiguredChar getOffset_8() {
return offset_8;
}
public ConfiguredChar getOffset_16() {
return offset_16;
}
public ConfiguredChar getOffset_32() {
return offset_32;
}
public ConfiguredChar getOffset_64() {
return offset_64;
}
public ConfiguredChar getOffset_128() {
return offset_128;
}
public ConfiguredChar getRight() {
return right;
}
public static Builder builder() {
return new Builder();
}
public String getBackGroundImage(int n) {
String offset = OffsetFont.getShortestNegChars(n + rightMargin + 2);
n = n + leftMargin + rightMargin + 2;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.getCharacter());
while (n >= 128) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_8.getCharacter());
n -= 8;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_4.getCharacter());
n -= 4;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_1.getCharacter());
}
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(right.getCharacter());
stringBuilder.append(offset);
return stringBuilder.toString();
}
public static class Builder {
private final BackGround backGround;
public static Builder of() {
return new Builder();
}
public Builder() {
this.backGround = new BackGround();
}
public Builder left(ConfiguredChar configuredChar) {
backGround.left = configuredChar;
return this;
}
public Builder right(ConfiguredChar configuredChar) {
backGround.right = configuredChar;
return this;
}
public Builder offset_1(ConfiguredChar configuredChar) {
backGround.offset_1 = configuredChar;
return this;
}
public Builder offset_2(ConfiguredChar configuredChar) {
backGround.offset_2 = configuredChar;
return this;
}
public Builder offset_4(ConfiguredChar configuredChar) {
backGround.offset_4 = configuredChar;
return this;
}
public Builder offset_8(ConfiguredChar configuredChar) {
backGround.offset_8 = configuredChar;
return this;
}
public Builder offset_16(ConfiguredChar configuredChar) {
backGround.offset_16 = configuredChar;
return this;
}
public Builder offset_32(ConfiguredChar configuredChar) {
backGround.offset_32 = configuredChar;
return this;
}
public Builder offset_64(ConfiguredChar configuredChar) {
backGround.offset_64 = configuredChar;
return this;
}
public Builder offset_128(ConfiguredChar configuredChar) {
backGround.offset_128 = configuredChar;
return this;
}
public Builder leftMargin(int margin) {
backGround.leftMargin = margin;
return this;
}
public Builder rightMargin(int margin) {
backGround.rightMargin = margin;
return this;
}
public BackGround build() {
return backGround;
}
}
}

View File

@@ -0,0 +1,25 @@
package net.momirealms.customnameplates.api.mechanic.character;
public class CharacterArranger {
public static char currentChar;
public static void increase() {
currentChar = (char) (currentChar + '\u0001');
}
public static char getAndIncrease() {
char temp = currentChar;
increase();
return temp;
}
public static char increaseAndGet() {
increase();
return currentChar;
}
public static void reset(char c) {
currentChar = c;
}
}

View File

@@ -0,0 +1,107 @@
package net.momirealms.customnameplates.api.mechanic.character;
import net.momirealms.customnameplates.api.util.LogUtils;
public class ConfiguredChar {
private char character;
private String pngFile;
private int height;
private int width;
private int ascent;
private ConfiguredChar() {
}
public ConfiguredChar(char character, String pngFile, int height, int width, int ascent) {
this.character = character;
this.pngFile = pngFile;
this.height = height;
this.width = width;
this.ascent = ascent;
}
public char getCharacter() {
return character;
}
public static Builder builder() {
return new Builder();
}
public String getPngFile() {
return pngFile;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getAscent() {
return ascent;
}
public String getFile() {
return pngFile + ".png";
}
public static class Builder {
private final ConfiguredChar configuredChar;
public static Builder of() {
return new Builder();
}
public Builder() {
this.configuredChar = new ConfiguredChar();
}
public Builder character(char character) {
configuredChar.character = character;
return this;
}
public Builder png(String png) {
configuredChar.pngFile = png;
return this;
}
public Builder height(int height) {
configuredChar.height = height;
return this;
}
public Builder ascent(int ascent) {
configuredChar.ascent = ascent;
if (ascent >= configuredChar.height) {
LogUtils.warn("Invalid config for " + configuredChar.pngFile);
LogUtils.warn("Ascent " + ascent + " should be no higher than Height " + configuredChar.height);
}
return this;
}
public Builder descent(int descent) {
if (descent < 0) {
LogUtils.warn("Invalid config for " + configuredChar.pngFile);
LogUtils.warn("Descent " + descent + " should be no lower than 0");
}
configuredChar.ascent = configuredChar.height - descent;
return this;
}
public Builder width(int width) {
configuredChar.width = width;
return this;
}
public ConfiguredChar build() {
return configuredChar;
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.font;
public enum OffsetFont {
NEG_1('\uf801', -1, -3),
NEG_2('\uf802', -2, -4),
NEG_3('\uf803', -3, -5),
NEG_4('\uf804', -4, -6),
NEG_5('\uf805', -5, -7),
NEG_6('\uf806', -6, -8),
NEG_7('\uf807', -7, -9),
NEG_8('\uf808', -8, -10),
NEG_16('\uf809', -16, -18),
NEG_32('\uf80a', -32, -34),
NEG_64('\uf80b', -64, -66),
NEG_128('\uf80c', -128, -130),
POS_1('\uf811', 1, -1),
POS_2('\uf812', 2, 1),
POS_3('\uf813', 3, 2),
POS_4('\uf814', 4, 3),
POS_5('\uf815', 5, 4),
POS_6('\uf816', 6, 5),
POS_7('\uf817', 7, 6),
POS_8('\uf818', 8, 7),
POS_16('\uf819', 16, 15),
POS_32('\uf81a', 32, 31),
POS_64('\uf81b', 64, 63),
POS_128('\uf81c', 128, 127);
private final char character;
private final int space;
private final int height;
OffsetFont(char character, int space, int height) {
this.character = character;
this.space = space;
this.height = height;
}
public char getCharacter() {
return this.character;
}
public int getSpace() {
return this.space;
}
public int getHeight() {
return this.height;
}
public static String getOffsetChars(int offset) {
if (offset >= 0) {
return getShortestPosChars(offset);
} else {
return getShortestNegChars(-offset);
}
}
public static String getShortestNegChars(int n) {
StringBuilder stringBuilder = new StringBuilder();
while (n >= 128) {
stringBuilder.append(OffsetFont.NEG_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_8.getCharacter());
n -= 8;
}
if (n - 7 >= 0) {
stringBuilder.append(OffsetFont.NEG_7.getCharacter());
n -= 7;
}
if (n - 6 >= 0) {
stringBuilder.append(OffsetFont.NEG_6.getCharacter());
n -= 6;
}
if (n - 5 >= 0) {
stringBuilder.append(OffsetFont.NEG_5.getCharacter());
n -= 5;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_4.getCharacter());
n -= 4;
}
if (n - 3 >= 0) {
stringBuilder.append(OffsetFont.NEG_3.getCharacter());
n -= 3;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
}
return stringBuilder.toString();
}
public static String getShortestPosChars(int n) {
StringBuilder stringBuilder = new StringBuilder();
while (n >= 128) {
stringBuilder.append(OffsetFont.POS_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.POS_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.POS_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.POS_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.POS_8.getCharacter());
n -= 8;
}
if (n - 7 >= 0) {
stringBuilder.append(OffsetFont.POS_7.getCharacter());
n -= 7;
}
if (n - 6 >= 0) {
stringBuilder.append(OffsetFont.POS_6.getCharacter());
n -= 6;
}
if (n - 5 >= 0) {
stringBuilder.append(OffsetFont.POS_5.getCharacter());
n -= 5;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.POS_4.getCharacter());
n -= 4;
}
if (n - 3 >= 0) {
stringBuilder.append(OffsetFont.POS_3.getCharacter());
n -= 3;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.POS_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.POS_1.getCharacter());
}
return stringBuilder.toString();
}
}

View File

@@ -0,0 +1,111 @@
package net.momirealms.customnameplates.api.mechanic.misc;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class ViewerText {
private final Player owner;
private String processedText;
private final ClaimedText[] placeholders;
private final ConcurrentHashMap<UUID, String> valueMap;
public ViewerText(Player owner, String rawText) {
this.processedText = rawText;
this.valueMap = new ConcurrentHashMap<>();
this.owner = owner;
List<String> placeholders = CustomNameplatesPlugin.get().getPlaceholderManager().detectPlaceholders(rawText);
this.placeholders = new ClaimedText[placeholders.size()];
int i = 0;
for (String placeholder : placeholders) {
processedText = processedText.replace(placeholder, "%s");
if (placeholder.startsWith("%viewer_")) {
this.placeholders[i] = new ClaimedText(null, "%" + placeholder.substring("%viewer_".length()));
} else {
this.placeholders[i] = new ClaimedText(owner, placeholder);
}
i++;
}
}
public void updateForOwner() {
for (ClaimedText text : placeholders) {
text.update();
}
}
public boolean updateForViewer(Player viewer) {
String string;
if ("%s".equals(processedText)) {
string = placeholders[0].getValue(viewer);
} else if (placeholders.length != 0) {
Object[] values = new String[placeholders.length];
for (int i = 0; i < placeholders.length; i++) {
values[i] = placeholders[i].getValue(viewer);
}
string = String.format(processedText, values);
} else {
string = processedText;
}
var uuid = viewer.getUniqueId();
if (!valueMap.containsKey(uuid)) {
valueMap.put(uuid, string);
return true;
}
String previousValue = valueMap.get(uuid);
if (!previousValue.equals(string)) {
valueMap.put(uuid, string);
return true;
}
return false;
}
public void removeViewer(Player viewer) {
valueMap.remove(viewer.getUniqueId());
}
public String getProcessedText() {
return processedText;
}
public String getLatestValue(Player viewer) {
return valueMap.get(viewer.getUniqueId());
}
public Entity getOwner() {
return owner;
}
public static class ClaimedText {
private final String placeholder;
private final Player owner;
private String latestValue;
public ClaimedText(Player owner, String placeholder) {
this.placeholder = placeholder;
this.owner = owner;
this.latestValue = null;
this.update();
}
public void update() {
if (owner == null) return;
this.latestValue = PlaceholderAPI.setPlaceholders(owner, placeholder);
}
public String getValue(Player viewer) {
return Objects.requireNonNullElseGet(
latestValue,
() -> PlaceholderAPI.setPlaceholders(owner == null ? viewer : owner, placeholder)
);
}
}
}

View File

@@ -0,0 +1,70 @@
package net.momirealms.customnameplates.api.mechanic.nameplate;
import net.momirealms.customnameplates.api.mechanic.team.TeamColor;
public class CachedNameplate {
private TeamColor teamColor;
private String tagPrefix;
private String tagSuffix;
private String namePrefix;
private String nameSuffix;
private String playerName;
public CachedNameplate() {
this.tagPrefix = "";
this.tagSuffix = "";
this.namePrefix = "";
this.nameSuffix = "";
this.playerName = "";
this.teamColor = TeamColor.WHITE;
}
public String getTagPrefix() {
return tagPrefix;
}
public void setTagPrefix(String prefix) {
this.tagPrefix = prefix;
}
public String getTagSuffix() {
return tagSuffix;
}
public void setTagSuffix(String suffix) {
this.tagSuffix = suffix;
}
public void setNamePrefix(String namePrefix) {
this.namePrefix = namePrefix;
}
public void setNameSuffix(String nameSuffix) {
this.nameSuffix = nameSuffix;
}
public String getNamePrefix() {
return namePrefix;
}
public String getNameSuffix() {
return nameSuffix;
}
public TeamColor getTeamColor() {
return teamColor;
}
public void setTeamColor(TeamColor teamColor) {
this.teamColor = teamColor;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
}

View File

@@ -0,0 +1,166 @@
package net.momirealms.customnameplates.api.mechanic.nameplate;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.mechanic.team.TeamColor;
import net.momirealms.customnameplates.api.util.FontUtils;
public class Nameplate {
private String displayName;
private TeamColor teamColor;
private String namePrefix;
private String nameSuffix;
private ConfiguredChar left;
private ConfiguredChar middle;
private ConfiguredChar right;
private Nameplate() {
}
public Nameplate(
String displayName,
TeamColor teamColor,
String namePrefix,
String nameSuffix,
ConfiguredChar left,
ConfiguredChar middle,
ConfiguredChar right
) {
this.displayName = displayName;
this.teamColor = teamColor;
this.left = left;
this.middle = middle;
this.right = right;
this.namePrefix = namePrefix;
this.nameSuffix = nameSuffix;
}
public String getDisplayName() {
return displayName;
}
public TeamColor getTeamColor() {
return teamColor;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getMiddle() {
return middle;
}
public ConfiguredChar getRight() {
return right;
}
public String getNamePrefix() {
if (teamColor == TeamColor.NONE) {
return "";
}
if (teamColor == TeamColor.CUSTOM) {
return namePrefix;
}
return "<" + teamColor.name() + ">";
}
public String getNameSuffix() {
if (teamColor == TeamColor.NONE) {
return "";
}
if (teamColor == TeamColor.CUSTOM) {
return nameSuffix;
}
return "</" + teamColor.name() + ">";
}
public static Builder builder() {
return new Builder();
}
public String getPrefixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getPrefix(textWidth));
}
public String getPrefix(int textWidth) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth % 2 == 0 ? textWidth + left.getWidth() : textWidth + left.getWidth() + 1));
stringBuilder.append(left.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
int mid_amount = (textWidth - 1) / (middle.getWidth());
if (mid_amount != 0) {
for (int i = 0; i < mid_amount; i++) {
stringBuilder.append(middle.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - textWidth % middle.getWidth())); // +1
}
stringBuilder.append(middle.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(right.getCharacter());
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + right.getWidth() - 1)); // -1
return stringBuilder.toString();
}
public String getSuffixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getSuffix(textWidth));
}
public String getSuffix(int textWidth) {
return OffsetFont.getShortestNegChars(textWidth + textWidth % 2 + 1);
}
public static class Builder {
private final Nameplate nameplate;
public Builder() {
this.nameplate = new Nameplate();
}
public static Builder of() {
return new Builder();
}
public Builder displayName(String display) {
nameplate.displayName = display;
return this;
}
public Builder teamColor(TeamColor teamColor) {
nameplate.teamColor = teamColor;
return this;
}
public Builder namePrefix(String namePrefix) {
nameplate.namePrefix = namePrefix;
return this;
}
public Builder nameSuffix(String nameSuffix) {
nameplate.nameSuffix = nameSuffix;
return this;
}
public Builder left(ConfiguredChar configuredChar) {
nameplate.left = configuredChar;
return this;
}
public Builder middle(ConfiguredChar configuredChar) {
nameplate.middle = configuredChar;
return this;
}
public Builder right(ConfiguredChar configuredChar) {
nameplate.right = configuredChar;
return this;
}
public Nameplate build() {
return nameplate;
}
}
}

View File

@@ -0,0 +1,7 @@
package net.momirealms.customnameplates.api.mechanic.nameplate;
public enum TagMode {
TEAM,
UNLIMITED,
DISABLE
}

View File

@@ -0,0 +1,65 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.background.BackGround;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class BackGroundText {
private String text;
private BackGround backGround;
private BackGroundText() {
}
public BackGroundText(String text, BackGround backGround) {
this.text = text;
this.backGround = backGround;
}
public String getText() {
return text;
}
public BackGround getBackGround() {
return backGround;
}
public String getValue(OfflinePlayer player) {
String parsed = PlaceholderAPI.setPlaceholders(player, text);
int parsedWidth = FontUtils.getTextWidth(parsed);
return backGround.getBackGroundImage(parsedWidth) + parsed;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final BackGroundText text;
public Builder() {
this.text = new BackGroundText();
}
public static Builder of() {
return new Builder();
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder background(BackGround backGround) {
text.backGround = backGround;
return this;
}
public BackGroundText build() {
return text;
}
}
}

View File

@@ -0,0 +1,54 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
public class CachedText {
private long refreshInterval;
private String text;
private CachedText() {
}
public CachedText(long refreshInterval, String text) {
this.refreshInterval = refreshInterval;
this.text = text;
}
public long getRefreshInterval() {
return refreshInterval;
}
public String getText() {
return text;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final CachedText text;
public Builder() {
this.text = new CachedText();
}
public static Builder of() {
return new Builder();
}
public Builder refreshInterval(long time) {
this.text.refreshInterval = time;
return this;
}
public Builder text(String text) {
this.text.text = text;
return this;
}
public CachedText build() {
return text;
}
}
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.common.Pair;
import net.momirealms.customnameplates.api.manager.RequirementManager;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.requirement.Requirement;
import org.bukkit.OfflinePlayer;
import java.util.List;
public class ConditionalText {
private List<Pair<String, Requirement[]>> textList;
private ConditionalText() {
}
public ConditionalText(List<Pair<String, Requirement[]>> textList) {
this.textList = textList;
}
public static Builder builder() {
return new Builder();
}
public String getValue(OfflinePlayer player) {
Condition condition = new Condition(player);
for (Pair<String, Requirement[]> pair : textList) {
if (RequirementManager.isRequirementMet(condition, pair.right())) {
return PlaceholderAPI.setPlaceholders(player, pair.left());
}
}
return "";
}
public static class Builder {
private final ConditionalText conditionalText;
public static Builder of() {
return new Builder();
}
public Builder() {
this.conditionalText = new ConditionalText();
}
public Builder textList(List<Pair<String, Requirement[]>> textList) {
conditionalText.textList = textList;
return this;
}
public ConditionalText build() {
return conditionalText;
}
}
}

View File

@@ -0,0 +1,68 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class DescentText {
private int ascent;
private String text;
private boolean isUnicode;
public DescentText(int ascent, String text, boolean isUnicode) {
this.ascent = ascent;
this.text = text;
this.isUnicode = isUnicode;
}
private DescentText() {
}
public static Builder builder() {
return new Builder();
}
public String getValue(OfflinePlayer player) {
var parsed = PlaceholderAPI.setPlaceholders(player, text);
return isUnicode ? FontUtils.surroundAscentUnicodeFont(parsed, ascent) : FontUtils.surroundAscentFont(parsed, ascent);
}
public static class Builder {
private final DescentText descentText;
public static Builder of() {
return new Builder();
}
public Builder() {
this.descentText = new DescentText();
}
public Builder ascent(int ascent) {
descentText.ascent = ascent;
return this;
}
public Builder descent(int descent) {
descentText.ascent = 8 - descent;
return this;
}
public Builder text(String text) {
descentText.text = text;
return this;
}
public Builder unicode(boolean unicode) {
descentText.isUnicode = unicode;
return this;
}
public DescentText build() {
return descentText;
}
}
}

View File

@@ -0,0 +1,71 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class NameplateText {
private String text;
private Nameplate nameplate;
private NameplateText() {
}
public NameplateText(String text, Nameplate nameplate) {
this.text = text;
this.nameplate = nameplate;
}
public String getText() {
return text;
}
public Nameplate getNameplate() {
return nameplate;
}
public String getValue(OfflinePlayer player) {
String temp;
switch (nameplate.getTeamColor()) {
case CUSTOM -> temp = nameplate.getNamePrefix() + text + nameplate.getNameSuffix();
case NONE -> temp = text;
default -> temp = "<" + nameplate.getTeamColor().name() + ">" + text + "</" + nameplate.getTeamColor().name() + ">";
}
String parsed = PlaceholderAPI.setPlaceholders(player, temp);
int parsedWidth = FontUtils.getTextWidth(parsed);
return nameplate.getPrefixWithFont(parsedWidth) + parsed + nameplate.getSuffixWithFont(parsedWidth);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final NameplateText text;
public Builder() {
this.text = new NameplateText();
}
public static Builder of() {
return new Builder();
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder nameplate(Nameplate value) {
text.nameplate = value;
return this;
}
public NameplateText build() {
return text;
}
}
}

View File

@@ -0,0 +1,98 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class StaticText {
private String text;
private int value;
private StaticState staticState;
private StaticText() {
}
public StaticText(String text, int value, StaticState staticState) {
this.text = text;
this.value = value;
this.staticState = staticState;
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
public static Builder builder() {
return new Builder();
}
public StaticState getStaticState() {
return staticState;
}
public String getValue(OfflinePlayer player) {
String parsed = PlaceholderAPI.setPlaceholders(player, text);
int parsedWidth = FontUtils.getTextWidth(parsed);
switch (staticState) {
case LEFT -> {
return parsed + FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(value - parsedWidth));
}
case RIGHT -> {
return FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(value - parsedWidth)) + parsed;
}
case MIDDLE -> {
int half = (value - parsedWidth) / 2;
String left = FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(half));
String right = FontUtils.surroundNameplateFont(OffsetFont.getOffsetChars(value - parsedWidth - half));
return left + parsed + right;
}
default -> {
return "";
}
}
}
public static class Builder {
private final StaticText text;
public Builder() {
this.text = new StaticText();
}
public static Builder of() {
return new Builder();
}
public Builder value(int value) {
text.value = value;
return this;
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder state(StaticState state) {
text.staticState = state;
return this;
}
public StaticText build() {
return text;
}
}
public enum StaticState {
LEFT,
MIDDLE,
RIGHT
}
}

View File

@@ -0,0 +1,63 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.entity.Player;
import java.util.HashMap;
public class SwitchText {
private HashMap<String, String> valueMap;
private String toParse;
private String defaultValue;
public static Builder builder() {
return new Builder();
}
private SwitchText() {
}
public SwitchText(HashMap<String, String> valueMap, String toParse) {
this.valueMap = valueMap;
this.toParse = toParse;
}
public String getValue(Player player) {
String parsed = PlaceholderAPI.setPlaceholders(player, toParse);
return valueMap.getOrDefault(parsed, defaultValue);
}
public static class Builder {
private final SwitchText switchText;
public Builder() {
this.switchText = new SwitchText();
}
public static Builder of() {
return new Builder();
}
public Builder toParse(String toParse) {
this.switchText.toParse = toParse;
return this;
}
public Builder defaultValue(String value) {
this.switchText.defaultValue = value;
return this;
}
public Builder valueMap(HashMap<String, String> valueMap) {
this.switchText.valueMap = valueMap;
return this;
}
public SwitchText build() {
return switchText;
}
}
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.util.FontUtils;
import net.momirealms.customnameplates.api.util.LogUtils;
import org.bukkit.entity.Player;
public class VanillaHud {
private final char empty;
private final char half;
private final char full;
private final String maxPapi;
private final String currentPapi;
private final boolean reverse;
public VanillaHud(String empty, String half, String full, String maxPapi, String currentPapi, boolean reverse) {
this.empty = CustomNameplatesPlugin.get().getImageManager().getImage(empty).getCharacter();
this.half = CustomNameplatesPlugin.get().getImageManager().getImage(half).getCharacter();
this.full = CustomNameplatesPlugin.get().getImageManager().getImage(full).getCharacter();
this.maxPapi = maxPapi;
this.currentPapi = currentPapi;
this.reverse = reverse;
}
public String getValue(Player player) {
double current;
double max;
try {
current= Double.parseDouble(PlaceholderAPI.setPlaceholders(player, currentPapi));
max = Double.parseDouble(PlaceholderAPI.setPlaceholders(player, maxPapi));
} catch (NumberFormatException e) {
current = 1;
max = 1;
LogUtils.warn("Invalid number format when parsing: " + currentPapi + "/" + maxPapi);
}
if (current >= max) current = max;
if (current < 0) current = 0;
int point = (int) ((current / max) * 20);
int full_amount = point / 2;
int half_amount = point % 2;
int empty_amount = 10 - full_amount - half_amount;
StringBuilder builder = new StringBuilder();
if (reverse) {
builder
.append(String.valueOf(empty).repeat(empty_amount))
.append(String.valueOf(half).repeat(half_amount))
.append(String.valueOf(full).repeat(full_amount));
} else {
builder
.append(String.valueOf(full).repeat(full_amount))
.append(String.valueOf(half).repeat(half_amount))
.append(String.valueOf(empty).repeat(empty_amount));
}
return FontUtils.surroundNameplateFont(builder.toString());
}
}

View File

@@ -0,0 +1,13 @@
package net.momirealms.customnameplates.api.mechanic.tag;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import org.bukkit.entity.Player;
public interface NameplatePlayer {
void preview();
void preview(Nameplate nameplate);
Player getOwner();
}

View File

@@ -0,0 +1,109 @@
package net.momirealms.customnameplates.api.mechanic.tag.team;
import net.kyori.adventure.text.Component;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.manager.TeamTagManager;
import net.momirealms.customnameplates.api.mechanic.misc.ViewerText;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.api.mechanic.team.TeamColor;
import net.momirealms.customnameplates.api.mechanic.team.TeamTagVisibility;
import org.bukkit.entity.Player;
import java.util.Vector;
public class TeamPlayer implements NameplatePlayer {
private final TeamTagManager manager;
private final Player owner;
private final ViewerText prefix;
private final ViewerText suffix;
private final Vector<Player> nearbyPlayers;
public TeamPlayer(TeamTagManager manager, Player owner, String prefix, String suffix) {
this.manager = manager;
this.owner = owner;
this.prefix = new ViewerText(owner, prefix);
this.suffix = new ViewerText(owner, suffix);
this.nearbyPlayers = new Vector<>();
this.prefix.updateForOwner();
this.suffix.updateForOwner();
}
public void updateForNearbyPlayers(boolean force) {
this.prefix.updateForOwner();
this.suffix.updateForOwner();
for (Player viewer : nearbyPlayers) {
updateForOne(viewer, force);
}
}
public void removeNearbyPlayer(Player player) {
if (!nearbyPlayers.contains(player)) {
return;
}
nearbyPlayers.remove(player);
removeForOne(player);
prefix.removeViewer(player);
suffix.removeViewer(player);
}
public void addNearbyPlayer(Player player) {
if (nearbyPlayers.contains(player)) {
return;
}
nearbyPlayers.add(player);
updateForOne(player, false);
}
public void destroy() {
manager.removeTeamPlayerFromMap(owner.getUniqueId());
for (Player viewer : nearbyPlayers) {
removeForOne(viewer);
}
nearbyPlayers.clear();
}
private void updateForOne(Player viewer, boolean force) {
try {
if ((prefix.updateForViewer(viewer) | suffix.updateForViewer(viewer)) || force) {
CustomNameplatesPlugin.get().getTeamManager().updateTeam(
owner,
viewer,
CustomNameplatesPlugin.get().getAdventure().getComponentFromMiniMessage(prefix.getLatestValue(viewer)),
CustomNameplatesPlugin.get().getAdventure().getComponentFromMiniMessage(suffix.getLatestValue(viewer)),
CustomNameplatesPlugin.get().getNameplateManager().getTeamColor(owner),
TeamTagVisibility.ALWAYS
);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void removeForOne(Player viewer) {
CustomNameplatesPlugin.get().getTeamManager().updateTeam(
owner,
viewer,
Component.text(""),
Component.text(""),
TeamColor.WHITE,
TeamTagVisibility.ALWAYS
);
}
@Override
public void preview() {
}
@Override
public void preview(Nameplate nameplate) {
}
@Override
public Player getOwner() {
return owner;
}
}

View File

@@ -0,0 +1,60 @@
package net.momirealms.customnameplates.api.mechanic.tag.unlimited;
import net.momirealms.customnameplates.api.mechanic.misc.ViewerText;
import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
import java.util.UUID;
public interface NamedEntity {
boolean canSee(Player viewer);
void timer();
boolean canShow();
boolean isShownTo(Player viewer);
void spawn(Player viewer, Pose pose);
void spawn(Pose pose);
void destroy();
void destroy(Player viewer);
void teleport(double x, double y, double z, boolean onGround);
void teleport(Player viewer, double x, double y, double z, boolean onGround);
void setSneak(boolean sneaking, boolean respawn);
void removePlayerFromViewers(Player player);
void addPlayerToViewers(Player player);
double getOffset();
void setOffset(double v);
ViewerText getViewerText();
int getEntityId();
void move(short x, short y, short z, boolean onGround);
void move(Player viewer, short x, short y, short z, boolean onGround);
void respawn(Player viewer, Pose pose);
void respawn(Pose pose);
void updateText();
void updateText(Player viewer);
UUID getUuid();
void handlePose(Pose previous, Pose pose);
}

View File

@@ -0,0 +1,39 @@
package net.momirealms.customnameplates.api.mechanic.tag.unlimited;
import net.momirealms.customnameplates.api.manager.UnlimitedTagManager;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
import java.util.Vector;
public abstract class UnlimitedObject {
protected final UnlimitedTagManager manager;
protected final Entity entity;
protected final Vector<Player> nearbyPlayers;
public UnlimitedObject(UnlimitedTagManager manager, Entity entity) {
this.manager = manager;
this.entity = entity;
this.nearbyPlayers = new Vector<>();
}
public Vector<Player> getNearbyPlayers() {
return nearbyPlayers;
}
public abstract void addNearbyPlayer(Player player);
public abstract void removeNearbyPlayer(Player player);
public abstract void move(Player receiver, short x, short y, short z, boolean onGround);
public abstract void teleport(Player receiver, double x, double y, double z, boolean onGround);
public abstract void destroy();
public abstract void sneak(boolean sneaking, boolean flying);
public abstract void handlePose(Pose previous, Pose pose);
}

View File

@@ -0,0 +1,201 @@
package net.momirealms.customnameplates.api.mechanic.tag.unlimited;
import net.kyori.adventure.text.Component;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.manager.UnlimitedTagManager;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.api.mechanic.team.TeamColor;
import net.momirealms.customnameplates.api.mechanic.team.TeamTagVisibility;
import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
import java.util.Vector;
public class UnlimitedPlayer extends UnlimitedObject implements NameplatePlayer {
private final Player owner;
private final Vector<NamedEntity> tags;
private double hatOffset;
public UnlimitedPlayer(UnlimitedTagManager manager, Player player) {
super(manager, player);
this.owner = player;
this.tags = new Vector<>();
}
/**
* Add a tag for a player
*
* @param tag tag
*/
public void addTag(NamedEntity tag) {
if (tags.contains(tag)) {
return;
}
tags.add(tag);
for (Player all : nearbyPlayers) {
if (tag.canShow() && tag.canSee(all)) {
tag.addPlayerToViewers(all);
}
}
}
/**
* Remove a tag for a player
*
* @param tag tag
*/
public void removeTag(NamedEntity tag) {
if (tags.remove(tag)) {
tag.destroy();
}
}
/**
* Get the tags that player own
*
* @return tags
*/
public Vector<NamedEntity> getTags() {
return tags;
}
/**
* Set hat offset. This is useful for cosmetics plugins
* because hat might hide the name tags
*
* @param hatOffset hat offset
*/
public void setHatOffset(double hatOffset) {
this.hatOffset = hatOffset;
}
@Override
public void preview() {
}
@Override
public void preview(Nameplate nameplate) {
}
/**
* Get the owner
*/
@Override
public Player getOwner() {
return owner;
}
/**
* Get the hat offset
*/
public double getHatOffset() {
return hatOffset;
}
/**
* Add a nearby player so he could see the tag
* This process is automatically handled by CustomNameplates
*
* @param player player
*/
@Override
public void addNearbyPlayer(Player player) {
if (nearbyPlayers.contains(player)) {
return;
}
nearbyPlayers.add(player);
addForOne(player);
for (NamedEntity tag : tags) {
if (tag.canShow() && tag.canSee(player)) {
tag.addPlayerToViewers(player);
}
}
}
/**
* Remove a nearby player so he would no longer receive tag updates
* This process is automatically handled by CustomNameplates
*
* @param player player
*/
@Override
public void removeNearbyPlayer(Player player) {
if (!nearbyPlayers.contains(player)) {
return;
}
super.nearbyPlayers.remove(player);
removeForOne(player);
for (NamedEntity tag : tags) {
tag.removePlayerFromViewers(player);
}
}
@Override
public void destroy() {
manager.removeUnlimitedObjectFromMap(entity.getUniqueId());
for (Player viewer : nearbyPlayers) {
removeForOne(viewer);
}
for (NamedEntity tag : tags) {
tag.destroy();
}
nearbyPlayers.clear();
tags.clear();
}
public void move(Player receiver, short x, short y, short z, boolean onGround) {
for (NamedEntity tag : tags) {
tag.move(receiver, x, y, z, onGround);
}
}
public void teleport(Player receiver, double x, double y, double z, boolean onGround) {
for (NamedEntity tag : tags) {
tag.teleport(receiver, x, y, z, onGround);
}
}
public void sneak(boolean sneaking, boolean flying) {
for (NamedEntity tag : tags) {
tag.setSneak(sneaking, !flying);
}
}
public void handlePose(Pose previous, Pose pose) {
for (NamedEntity tag : tags) {
tag.handlePose(previous, pose);
}
}
private void addForOne(Player viewer) {
CustomNameplatesPlugin.get().getTeamManager().updateTeam(
owner,
viewer,
Component.text(""),
Component.text(""),
TeamColor.WHITE,
TeamTagVisibility.NEVER
);
}
private void removeForOne(Player viewer) {
CustomNameplatesPlugin.get().getTeamManager().updateTeam(
owner,
viewer,
Component.text(""),
Component.text(""),
TeamColor.WHITE,
TeamTagVisibility.ALWAYS
);
}
public void timer() {
for (NamedEntity tag : tags) {
tag.timer();
}
}
}

View File

@@ -0,0 +1,106 @@
package net.momirealms.customnameplates.api.mechanic.tag.unlimited;
import net.momirealms.customnameplates.api.requirement.Requirement;
public class UnlimitedTagSetting {
private double verticalOffset;
private String rawText;
private int checkFrequency;
private int refreshFrequency;
private Requirement[] viewerRequirements;
private Requirement[] ownerRequirements;
private UnlimitedTagSetting() {
verticalOffset = 0;
rawText = "";
checkFrequency = 10;
refreshFrequency = 10;
viewerRequirements = new Requirement[0];
ownerRequirements = new Requirement[0];
}
public UnlimitedTagSetting(double verticalOffset, String rawText, int checkFrequency, int refreshFrequency, Requirement[] viewerRequirements, Requirement[] ownerRequirements) {
this.verticalOffset = verticalOffset;
this.rawText = rawText;
this.checkFrequency = checkFrequency;
this.refreshFrequency = refreshFrequency;
this.viewerRequirements = viewerRequirements;
this.ownerRequirements = ownerRequirements;
}
public static Builder builder() {
return new Builder();
}
public double getVerticalOffset() {
return verticalOffset;
}
public String getRawText() {
return rawText;
}
public int getCheckFrequency() {
return checkFrequency;
}
public int getRefreshFrequency() {
return refreshFrequency;
}
public Requirement[] getViewerRequirements() {
return viewerRequirements;
}
public Requirement[] getOwnerRequirements() {
return ownerRequirements;
}
public static class Builder {
private final UnlimitedTagSetting setting;
public static Builder of() {
return new Builder();
}
public Builder() {
this.setting = new UnlimitedTagSetting();
}
public Builder checkFrequency(int checkFrequency) {
this.setting.checkFrequency = checkFrequency;
return this;
}
public Builder refreshFrequency(int refreshFrequency) {
this.setting.refreshFrequency = refreshFrequency;
return this;
}
public Builder rawText(String rawText) {
this.setting.rawText = rawText;
return this;
}
public Builder verticalOffset(double verticalOffset) {
this.setting.verticalOffset = verticalOffset;
return this;
}
public Builder ownerRequirements(Requirement[] ownerRequirements) {
this.setting.ownerRequirements = ownerRequirements;
return this;
}
public Builder viewerRequirements(Requirement[] viewerRequirements) {
this.setting.viewerRequirements = viewerRequirements;
return this;
}
public UnlimitedTagSetting build() {
return setting;
}
}
}

View File

@@ -0,0 +1,31 @@
package net.momirealms.customnameplates.api.mechanic.team;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public enum TeamCollisionRule {
ALWAYS("always"),
NEVER("never"),
PUSH_OTHER_TEAMS("pushOtherTeams"),
PUSH_OWN_TEAM("pushOwnTeam");
private final String id;
TeamCollisionRule(@NotNull String id) {
this.id = id;
}
public String getId() {
return id;
}
@NotNull
public static TeamCollisionRule byId(String id) {
return Arrays.stream(values())
.filter(mode -> mode.id.equals(id))
.findFirst()
.orElse(ALWAYS);
}
}

View File

@@ -0,0 +1,29 @@
package net.momirealms.customnameplates.api.mechanic.team;
import java.util.Locale;
public enum TeamColor {
NONE,
BLACK,
DARK_BLUE,
DARK_GREEN,
DARK_AQUA,
DARK_RED,
DARK_PURPLE,
GOLD,
GRAY,
DARK_GRAY,
BLUE,
GREEN,
AQUA,
RED,
LIGHT_PURPLE,
YELLOW,
WHITE,
CUSTOM;
public TeamColor getById(String id) throws IllegalArgumentException {
return valueOf(id.toUpperCase(Locale.ENGLISH));
}
}

View File

@@ -0,0 +1,154 @@
package net.momirealms.customnameplates.api.mechanic.team;
import net.kyori.adventure.text.Component;
import java.util.Collection;
import java.util.Collections;
public class TeamCreatePacket {
// String i
private String teamName;
// Collection<String> j
private Collection<String> members;
/*
Optional<b> k
*/
// IChatBaseComponent a
private Component teamDisplay;
// IChatBaseComponent b
private Component teamPrefix;
// IChatBaseComponent c
private Component teamSuffix;
// String d
private TeamTagVisibility tagVisibility;
// String e
private TeamCollisionRule collisionRule;
// Enum f
private TeamColor teamColor;
private TeamCreatePacket() {
this.teamName = "";
this.members = Collections.singleton("");
this.teamDisplay = Component.text("");
this.teamPrefix = Component.text("");
this.teamSuffix = Component.text("");
this.tagVisibility = TeamTagVisibility.ALWAYS;
this.collisionRule = TeamCollisionRule.ALWAYS;
this.teamColor = TeamColor.WHITE;
}
public TeamCreatePacket(
String teamName,
Collection<String> members,
Component teamDisplay,
Component teamPrefix,
Component teamSuffix,
TeamTagVisibility tagVisibility,
TeamCollisionRule collisionRule,
TeamColor teamColor
) {
this.teamName = teamName;
this.members = members;
this.teamDisplay = teamDisplay;
this.teamPrefix = teamPrefix;
this.teamSuffix = teamSuffix;
this.tagVisibility = tagVisibility;
this.collisionRule = collisionRule;
this.teamColor = teamColor;
}
public String getTeamName() {
return teamName;
}
public Collection<String> getMembers() {
return members;
}
public Component getTeamDisplay() {
return teamDisplay;
}
public Component getTeamPrefix() {
return teamPrefix;
}
public Component getTeamSuffix() {
return teamSuffix;
}
public TeamTagVisibility getTagVisibility() {
return tagVisibility;
}
public TeamCollisionRule getCollisionRule() {
return collisionRule;
}
public TeamColor getTeamColor() {
return teamColor;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final TeamCreatePacket packet;
public Builder() {
this.packet = new TeamCreatePacket();
}
public static Builder of() {
return new Builder();
}
public Builder teamName(String name) {
packet.teamName = name;
return this;
}
public Builder members(Collection<String> members) {
packet.members = members;
return this;
}
public Builder display(Component display) {
packet.teamDisplay = display;
return this;
}
public Builder prefix(Component prefix) {
packet.teamPrefix = prefix;
return this;
}
public Builder suffix(Component suffix) {
packet.teamSuffix = suffix;
return this;
}
public Builder color(TeamColor color) {
packet.teamColor = color;
return this;
}
public Builder tagVisibility(TeamTagVisibility visibility) {
packet.tagVisibility = visibility;
return this;
}
public Builder collisionRule(TeamCollisionRule rule) {
packet.collisionRule = rule;
return this;
}
public TeamCreatePacket build() {
return packet;
}
}
}

View File

@@ -0,0 +1,39 @@
package net.momirealms.customnameplates.api.mechanic.team;
public class TeamRemovePacket {
private String teamName;
private TeamRemovePacket() {
}
public TeamRemovePacket(String teamName) {
this.teamName = teamName;
}
public String getTeamName() {
return teamName;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final TeamRemovePacket packet;
public Builder() {
this.packet = new TeamRemovePacket();
}
public Builder teamName(String teamName) {
packet.teamName = teamName;
return this;
}
public TeamRemovePacket build() {
return packet;
}
}
}

View File

@@ -0,0 +1,31 @@
package net.momirealms.customnameplates.api.mechanic.team;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public enum TeamTagVisibility {
ALWAYS("always"),
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
HIDE_FOR_OWN_TEAM("hideForOwnTeam"),
NEVER("never");
private final String id;
TeamTagVisibility(@NotNull String id) {
this.id = id;
}
public String getId() {
return id;
}
@NotNull
public static TeamTagVisibility byId(String id) {
return Arrays.stream(values())
.filter(mode -> mode.id.equals(id))
.findFirst()
.orElse(ALWAYS);
}
}

View File

@@ -0,0 +1,136 @@
package net.momirealms.customnameplates.api.mechanic.team;
import net.kyori.adventure.text.Component;
public class TeamUpdatePacket {
private String teamName;
/*
Optional<b> k
*/
// IChatBaseComponent a
private Component teamDisplay;
// IChatBaseComponent b
private Component teamPrefix;
// IChatBaseComponent c
private Component teamSuffix;
// String d
private TeamTagVisibility tagVisibility;
// String e
private TeamCollisionRule collisionRule;
// Enum f
private TeamColor teamColor;
private TeamUpdatePacket() {
this.teamName = "";
this.teamDisplay = Component.text("");
this.teamPrefix = Component.text("");
this.teamSuffix = Component.text("");
this.tagVisibility = TeamTagVisibility.ALWAYS;
this.collisionRule = TeamCollisionRule.ALWAYS;
this.teamColor = TeamColor.WHITE;
}
public TeamUpdatePacket(
String teamName,
Component teamDisplay,
Component teamPrefix,
Component teamSuffix,
TeamTagVisibility tagVisibility,
TeamCollisionRule collisionRule,
TeamColor teamColor
) {
this.teamName = teamName;
this.teamDisplay = teamDisplay;
this.teamPrefix = teamPrefix;
this.teamSuffix = teamSuffix;
this.tagVisibility = tagVisibility;
this.collisionRule = collisionRule;
this.teamColor = teamColor;
}
public String getTeamName() {
return teamName;
}
public Component getTeamDisplay() {
return teamDisplay;
}
public Component getTeamPrefix() {
return teamPrefix;
}
public Component getTeamSuffix() {
return teamSuffix;
}
public TeamTagVisibility getTagVisibility() {
return tagVisibility;
}
public TeamCollisionRule getCollisionRule() {
return collisionRule;
}
public TeamColor getTeamColor() {
return teamColor;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final TeamUpdatePacket packet;
public Builder() {
this.packet = new TeamUpdatePacket();
}
public static Builder of() {
return new Builder();
}
public Builder teamName(String name) {
packet.teamName = name;
return this;
}
public Builder display(Component display) {
packet.teamDisplay = display;
return this;
}
public Builder prefix(Component prefix) {
packet.teamPrefix = prefix;
return this;
}
public Builder suffix(Component suffix) {
packet.teamSuffix = suffix;
return this;
}
public Builder color(TeamColor color) {
packet.teamColor = color;
return this;
}
public Builder tagVisibility(TeamTagVisibility visibility) {
packet.tagVisibility = visibility;
return this;
}
public Builder collisionRule(TeamCollisionRule rule) {
packet.collisionRule = rule;
return this;
}
public TeamUpdatePacket build() {
return packet;
}
}
}

View File

@@ -0,0 +1,16 @@
package net.momirealms.customnameplates.api.requirement;
import org.bukkit.OfflinePlayer;
public class Condition {
private final OfflinePlayer player;
public Condition(OfflinePlayer player) {
this.player = player;
}
public OfflinePlayer getOfflinePlayer() {
return player;
}
}

View File

@@ -15,10 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.object.requirements;
import org.bukkit.entity.Player;
package net.momirealms.customnameplates.api.requirement;
public interface Requirement {
boolean isConditionMet(Player player);
/**
* Is condition met the requirement
*
* @param condition condition
* @return meet or not
*/
boolean isConditionMet(Condition condition);
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.requirement;
/**
* An abstract class representing a requirement expansion
* Requirement expansions are used to define custom requirements for various functionalities.
*/
public abstract class RequirementExpansion {
/**
* Get the version of this requirement expansion.
*
* @return The version of the expansion.
*/
public abstract String getVersion();
/**
* Get the author of this requirement expansion.
*
* @return The author of the expansion.
*/
public abstract String getAuthor();
/**
* Get the type of requirement provided by this expansion.
*
* @return The type of requirement.
*/
public abstract String getRequirementType();
/**
* Get the factory for creating requirements defined by this expansion.
*
* @return The requirement factory.
*/
public abstract RequirementFactory getRequirementFactory();
}

View File

@@ -15,24 +15,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.object;
package net.momirealms.customnameplates.api.requirement;
import org.bukkit.entity.Player;
/**
* An interface for a requirement factory that builds requirements.
*/
public interface RequirementFactory {
public abstract class Function {
public void load() {
}
public void unload() {
}
public void disable() {
}
public void onJoin(Player player) {
}
public void onQuit(Player player) {
}
/**
* Build a requirement with the given arguments.
*
* @param args The arguments used to build the requirement.
* @return The built requirement.
*/
Requirement build(Object args);
}

View File

@@ -15,11 +15,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.object.scheduler;
package net.momirealms.customnameplates.api.scheduler;
public interface TimerTask {
public interface CancellableTask {
/**
* Cancel the task
*/
void cancel();
/**
* Get if the task is cancelled or not
*
* @return cancelled or not
*/
boolean isCancelled();
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.scheduler;
import org.bukkit.Location;
import java.util.concurrent.TimeUnit;
public interface Scheduler {
/**
* Runs a task synchronously on the main server thread or region thread.
*
* @param runnable The task to run.
* @param location The location associated with the task.
*/
void runTaskSync(Runnable runnable, Location location);
/**
* Runs a task synchronously with a specified delay and period.
*
* @param runnable The task to run.
* @param location The location associated with the task.
* @param delayTicks The delay in ticks before the first execution.
* @param periodTicks The period between subsequent executions in ticks.
* @return A CancellableTask for managing the scheduled task.
*/
CancellableTask runTaskSyncTimer(Runnable runnable, Location location, long delayTicks, long periodTicks);
/**
* Runs a task asynchronously with a specified delay.
*
* @param runnable The task to run.
* @param delay The delay before the task execution.
* @param timeUnit The time unit for the delay.
* @return A CancellableTask for managing the scheduled task.
*/
CancellableTask runTaskAsyncLater(Runnable runnable, long delay, TimeUnit timeUnit);
/**
* Runs a task asynchronously.
*
* @param runnable The task to run.
*/
void runTaskAsync(Runnable runnable);
/**
* Runs a task synchronously with a specified delay.
*
* @param runnable The task to run.
* @param location The location associated with the task.
* @param delay The delay before the task execution.
* @param timeUnit The time unit for the delay.
* @return A CancellableTask for managing the scheduled task.
*/
CancellableTask runTaskSyncLater(Runnable runnable, Location location, long delay, TimeUnit timeUnit);
/**
* Runs a task synchronously with a specified delay in ticks.
*
* @param runnable The task to run.
* @param location The location associated with the task.
* @param delayTicks The delay in ticks before the task execution.
* @return A CancellableTask for managing the scheduled task.
*/
CancellableTask runTaskSyncLater(Runnable runnable, Location location, long delayTicks);
/**
* Runs a task asynchronously with a specified delay and period.
*
* @param runnable The task to run.
* @param delay The delay before the first execution.
* @param period The period between subsequent executions.
* @param timeUnit The time unit for the delay and period.
* @return A CancellableTask for managing the scheduled task.
*/
CancellableTask runTaskAsyncTimer(Runnable runnable, long delay, long period, TimeUnit timeUnit);
}

View File

@@ -0,0 +1,76 @@
package net.momirealms.customnameplates.api.util;
public class FontUtils {
private static String namespace;
private static String font;
/**
* Surround the text with ascent font
*
* @param text text
* @param ascent ascent
* @return ascent font text
*/
public static String surroundAscentFont(String text, int ascent) {
return getAscentFontTag(ascent) + text + getFontTagCloser();
}
/**
* Surround the text with ascent unicode
*
* @param text text
* @param ascent ascent
* @return ascent font text
*/
public static String surroundAscentUnicodeFont(String text, int ascent) {
return getAscentUnicodeFontTag(ascent) + text + getFontTagCloser();
}
/**
* Surround the text with custom nameplates font
*
* @param text text
* @return font text
*/
public static String surroundNameplateFont(String text) {
return getMiniMessageFontTag() + text + getFontTagCloser();
}
private static String getAscentFontTag(int ascent) {
return "<font:" + namespace + ":ascent_" + ascent + ">";
}
private static String getAscentUnicodeFontTag(int ascent) {
return "<font:" + namespace + ":ascent_unicode_" + ascent + ">";
}
private static String getMiniMessageFontTag() {
return "<font:" + namespace + ":" + font + ">";
}
private static String getFontTagCloser() {
return "</font>";
}
/**
* Get a text's width
*
* @param text text
* @return width
*/
public static int getTextWidth(String text) {
return 0;
}
/**
* Set namespace and font
*
* @param n namespace
* @param f font
*/
public static void setNameSpaceAndFont(String n, String f) {
namespace = n;
font = f;
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.util;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Level;
public final class LogUtils {
/**
* Log an informational message.
*
* @param message The message to log.
*/
public static void info(@NotNull String message) {
CustomNameplatesPlugin.getInstance().getLogger().info(message);
}
/**
* Log a warning message.
*
* @param message The message to log.
*/
public static void warn(@NotNull String message) {
CustomNameplatesPlugin.getInstance().getLogger().warning(message);
}
/**
* Log a severe error message.
*
* @param message The message to log.
*/
public static void severe(@NotNull String message) {
CustomNameplatesPlugin.getInstance().getLogger().severe(message);
}
/**
* Log a warning message with a throwable exception.
*
* @param message The message to log.
* @param throwable The throwable exception to log.
*/
public static void warn(@NotNull String message, Throwable throwable) {
CustomNameplatesPlugin.getInstance().getLogger().log(Level.WARNING, message, throwable);
}
/**
* Log a severe error message with a throwable exception.
*
* @param message The message to log.
* @param throwable The throwable exception to log.
*/
public static void severe(@NotNull String message, Throwable throwable) {
CustomNameplatesPlugin.getInstance().getLogger().log(Level.SEVERE, message, throwable);
}
private LogUtils() {
throw new UnsupportedOperationException("This class cannot be instantiated");
}
}

View File

@@ -1,81 +0,0 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
group = 'net.momirealms'
version = '2.2.3.18.1'
repositories {
maven {name = "aliyun-repo"; url = "https://maven.aliyun.com/repository/public/"}
maven {name = "sk89q-repo"; url = "https://maven.enginehub.org/repo/"}
maven {name = 'sonatype'; url = 'https://oss.sonatype.org/content/groups/public/'}
maven {name = 'sonatype-snapshot'; url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'}
maven {name = "dmulloy2-repo"; url = "https://repo.dmulloy2.net/repository/public/"}
maven {name = "clip-repo"; url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/'}
maven {name = "jitpack"; url = 'https://jitpack.io'}
maven {name = "codecrafter47-repo"; url = 'https://nexus.codecrafter47.de/content/repositories/public/'}
maven {name = "opencollab-snapshot-repo"; url = 'https://repo.opencollab.dev/main/'}
maven {name = 'papermc-repo'; url = 'https://papermc.io/repo/repository/maven-public/'}
maven {name = 'William278-repo'; url = 'https://repo.william278.net/releases/'}
maven {name = 'kryptonmc-repo'; url = 'https://repo.kryptonmc.org/releases'}
mavenCentral()
}
dependencies {
compileOnly fileTree(dir:'libs',includes:['*.jar'])
compileOnly('dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT')
compileOnly ('me.clip:placeholderapi:2.11.3')
compileOnly ('com.zaxxer:HikariCP:5.0.1')
compileOnly ('commons-io:commons-io:2.11.0')
compileOnly ('dev.dejvokep:boosted-yaml:1.3.1')
compileOnly ("com.comphenix.protocol:ProtocolLib:5.1.0")
compileOnly ('net.md-5:bungeecord-api:1.19-R0.1-SNAPSHOT')
compileOnly ('com.github.LoneDev6:api-itemsadder:3.4.1-r4')
compileOnly ("com.velocitypowered:velocity-api:3.1.1")
compileOnly ('org.geysermc.geyser:api:2.2.0-SNAPSHOT')
compileOnly ("net.william278:velocitab:1.5.1")
compileOnly ('me.neznamy:tab-api:4.0.2')
compileOnly ('com.github.FrancoBM12:API-MagicCosmetics:2.2.5')
annotationProcessor ('com.velocitypowered:velocity-api:3.1.1')
compileOnly ('org.apache.commons:commons-lang3:3.12.0')
implementation ('net.kyori:adventure-api:4.14.0')
implementation ('net.kyori:adventure-platform-bukkit:4.3.3-SNAPSHOT')
implementation ('net.kyori:adventure-text-minimessage:4.14.0')
implementation ('net.kyori:adventure-text-serializer-gson:4.14.0')
implementation ("org.bstats:bstats-bukkit:3.0.1")
implementation fileTree (dir:'libs',includes:['BiomeAPI.jar'])
}
def targetJavaVersion = 17
java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
}
tasks.withType(JavaCompile).configureEach {
options.release = targetJavaVersion
options.encoding = "UTF-8"
}
processResources {
def props = [version: version]
inputs.properties props
filteringCharset 'UTF-8'
filesMatching('plugin.yml') {
expand props
}
}
shadowJar {
relocate ('net.kyori', 'net.momirealms.customnameplates.libs.net.kyori')
relocate ('org.bstats', 'net.momirealms.customnameplates.libs.org.bstats')
relocate ('net.momirealms.biomeapi', 'net.momirealms.customnameplates.libs.net.momirealms.biomeapi')
}
tasks.register("delete", Delete).get().delete("build/libs/"+project.name+"-"+project.version+".jar")
tasks.named("build").get().dependsOn("shadowJar").finalizedBy("delete").doLast {
println("Deleting: "+ "build/libs/"+project.name+"-"+project.version+".jar")
}

80
build.gradle.kts Normal file
View File

@@ -0,0 +1,80 @@
plugins {
id("java")
id("application")
id("maven-publish")
id("com.github.johnrengelman.shadow") version "8.1.1"
}
allprojects {
version = "2.3.0.0"
apply<JavaPlugin>()
apply(plugin = "java")
apply(plugin = "application")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "org.gradle.maven-publish")
application {
mainClass.set("")
}
repositories {
maven("https://maven.aliyun.com/repository/public/")
mavenCentral()
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://oss.sonatype.org/content/groups/public/")
maven("https://repo.dmulloy2.net/repository/public/")
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
maven("https://repo.codemc.org/repository/maven-public/")
maven("https://maven.enginehub.org/repo/")
maven("https://jitpack.io/")
maven("https://mvn.lumine.io/repository/maven-public/")
maven("https://repo.rapture.pw/repository/maven-releases/")
maven("https://nexus.phoenixdevt.fr/repository/maven-public/")
maven("https://r.irepo.space/maven/")
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://betonquest.org/nexus/repository/betonquest/")
maven("https://repo.william278.net/releases/")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
maven("https://repo.minebench.de/")
maven("https://repo.xenondevs.xyz/releases/")
maven("https://repo.kryptonmc.org/releases")
maven("https://repo.oraxen.com/releases")
}
}
subprojects {
tasks.processResources {
val props = mapOf("version" to version)
inputs.properties(props)
filteringCharset = "UTF-8"
filesMatching("*plugin.yml") {
expand(props)
}
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(17)
}
tasks.shadowJar {
destinationDirectory.set(file("$rootDir/target"))
archiveClassifier.set("")
archiveFileName.set("CustomNameplates-" + project.name + "-" + project.version + ".jar")
}
if ("api" == project.name) {
publishing {
publications {
create<MavenPublication>("mavenJava") {
groupId = "net.momirealms"
artifactId = "CustomNameplates"
version = rootProject.version.toString()
artifact(tasks.shadowJar)
}
}
}
}
}

42
bungeecord/.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@@ -0,0 +1,3 @@
dependencies {
}

View File

@@ -0,0 +1,9 @@
name: CustomNameplates
version: '${version}'
main: net.momirealms.customnameplates.paper.Main
api-version: 1.17
authors: [ XiaoMoMi ]
folia-supported: true
depend:
- ProtocolLib
- PlaceholderAPI

Binary file not shown.

View File

@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

35
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright ? 2015-2021 the original authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -32,10 +32,10 @@
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?,
# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?;
# * compound commands having a testable exit status, especially ?case?;
# * various built-in commands including ?command?, ?set?, and ?ulimit?.
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,10 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -143,12 +140,16 @@ fi
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
@@ -205,6 +210,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

15
gradlew.bat vendored
View File

@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

2
jitpack.yml Normal file
View File

@@ -0,0 +1,2 @@
jdk:
- openjdk17

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

42
paper/.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

62
paper/build.gradle.kts Normal file
View File

@@ -0,0 +1,62 @@
dependencies {
// server
compileOnly("dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT")
// command
compileOnly("dev.jorel:commandapi-bukkit-core:9.3.0")
// packet
compileOnly("com.comphenix.protocol:ProtocolLib:5.2.0-SNAPSHOT")
// papi
compileOnly("me.clip:placeholderapi:2.11.5")
// config
compileOnly("dev.dejvokep:boosted-yaml:1.3.1")
// team
compileOnly("me.neznamy:tab-api:4.0.2")
compileOnly(files("libs/CMI-API-9.6.5.0.jar"))
// Gson
compileOnly("com.google.code.gson:gson:2.10.1")
// database
compileOnly("org.xerial:sqlite-jdbc:3.43.0.0")
compileOnly("com.h2database:h2:2.2.224")
compileOnly("org.mongodb:mongodb-driver-sync:4.11.1")
compileOnly("com.zaxxer:HikariCP:5.0.1")
compileOnly("redis.clients:jedis:5.1.0")
// others
compileOnly("com.github.LoneDev6:api-itemsadder:3.5.0c-r5")
compileOnly("io.th0rgal:oraxen:1.165.0")
compileOnly("com.github.FrancoBM12:API-MagicCosmetics:2.2.5")
// chat channels
compileOnly(files("libs/VentureChat-3.7.1.jar"))
compileOnly(files("libs/TrChat-2.0.11.jar"))
// api module
implementation(project(":api"))
// adventure
implementation("net.kyori:adventure-api:4.15.0")
implementation("net.kyori:adventure-platform-bukkit:4.3.1")
implementation("net.kyori:adventure-text-minimessage:4.15.0")
implementation("net.kyori:adventure-text-serializer-legacy:4.15.0")
// bStats
implementation("org.bstats:bstats-bukkit:3.0.2")
// local lib
implementation(files("libs/BiomeAPI.jar"))
}
tasks {
shadowJar {
// relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
relocate ("org.bstats", "net.momirealms.customnameplates.libraries.bstats")
relocate ("net.momirealms.biomeapi", "net.momirealms.customnameplates.libraries.biomeapi")
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,147 @@
package net.momirealms.customnameplates.paper;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.event.CustomNameplatesReloadEvent;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.adventure.AdventureManagerImpl;
import net.momirealms.customnameplates.paper.command.CommandManager;
import net.momirealms.customnameplates.paper.helper.LibraryLoader;
import net.momirealms.customnameplates.paper.mechanic.actionbar.ActionBarManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.background.BackGroundManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.bossbar.BossBarManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.image.ImageManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.misc.CoolDownManager;
import net.momirealms.customnameplates.paper.mechanic.misc.PacketManager;
import net.momirealms.customnameplates.paper.mechanic.misc.VersionManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.nameplate.NameplateManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.pack.ResourcePackManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.placeholder.PlaceholderManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.requirement.RequirementManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.team.TeamManagerImpl;
import net.momirealms.customnameplates.paper.scheduler.SchedulerImpl;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.setting.CNLocale;
import net.momirealms.customnameplates.paper.storage.StorageManagerImpl;
import net.momirealms.customnameplates.paper.util.ReflectionUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.TimeZone;
public class CustomNameplatesPluginImpl extends CustomNameplatesPlugin {
private CoolDownManager coolDownManager;
private PacketManager packetManager;
@Override
public void onLoad() {
this.loadLibraries();
ReflectionUtils.load();
}
@Override
public void onEnable() {
this.adventureManager = new AdventureManagerImpl(this);
this.versionManager = new VersionManagerImpl(this);
this.scheduler = new SchedulerImpl(this);
this.storageManager = new StorageManagerImpl(this);
this.requirementManager = new RequirementManagerImpl(this);
this.bossBarManager = new BossBarManagerImpl(this);
this.imageManager = new ImageManagerImpl(this);
this.placeholderManager = new PlaceholderManagerImpl(this);
this.backGroundManager = new BackGroundManagerImpl(this);
this.resourcePackManager = new ResourcePackManagerImpl(this);
this.nameplateManager = new NameplateManagerImpl(this);
this.teamManager = new TeamManagerImpl(this);
this.actionBarManager = new ActionBarManagerImpl(this);
this.coolDownManager = new CoolDownManager(this);
this.packetManager = new PacketManager(this);
new CommandManager(this).load();
this.reload(CNConfig.generatePackOnStart);
this.versionManager.checkUpdate().thenAccept(outDated -> {
if (!outDated) this.getAdventure().sendConsoleMessage("[CustomNameplates] You are using the latest version.");
else this.getAdventure().sendConsoleMessage("[CustomNameplates] Update is available: <u>https://polymart.org/resource/2543<!u>");
});
}
@Override
public void onDisable() {
((SchedulerImpl) this.scheduler).shutdown();
((ActionBarManagerImpl) actionBarManager).unload();
((NameplateManagerImpl) this.nameplateManager).unload();
((TeamManagerImpl) this.teamManager).unload();
((BossBarManagerImpl) this.bossBarManager).unload();
((ImageManagerImpl) this.imageManager).unload();
((BackGroundManagerImpl) this.backGroundManager).unload();
((PlaceholderManagerImpl) this.placeholderManager).unload();
((RequirementManagerImpl) this.requirementManager).unload();
((ResourcePackManagerImpl) this.resourcePackManager).unload();
((StorageManagerImpl) this.storageManager).disable();
((AdventureManagerImpl) this.adventureManager).close();
}
@Override
public void reload(boolean generatePack) {
CNConfig.load();
CNLocale.load();
((SchedulerImpl) this.scheduler).reload();
((NameplateManagerImpl) this.nameplateManager).reload();
((BackGroundManagerImpl) this.backGroundManager).reload();
((TeamManagerImpl) this.teamManager).reload();
((StorageManagerImpl) this.storageManager).reload();
((RequirementManagerImpl) this.requirementManager).reload();
((BossBarManagerImpl) this.bossBarManager).reload();
((ActionBarManagerImpl) actionBarManager).reload();
((ImageManagerImpl) this.imageManager).reload();
((PlaceholderManagerImpl) this.placeholderManager).reload();
((ResourcePackManagerImpl) this.resourcePackManager).reload();
this.resourcePackManager.generateResourcePack();
CustomNameplatesReloadEvent event = new CustomNameplatesReloadEvent(this);
this.getServer().getPluginManager().callEvent(event);
}
@Override
public YamlConfiguration getConfig(String file) {
File config = new File(this.getDataFolder(), file);
if (!config.exists()) this.saveResource(file, false);
return YamlConfiguration.loadConfiguration(config);
}
@Override
public void debug(String s) {
if (CNConfig.debug) {
LogUtils.info(s);
}
}
public CoolDownManager getCoolDownManager() {
return coolDownManager;
}
private void loadLibraries() {
String mavenRepo = TimeZone.getDefault().getID().startsWith("Asia") ?
"https://maven.aliyun.com/repository/public/" : "https://repo.maven.apache.org/maven2/";
LibraryLoader.loadDependencies(
"org.apache.commons:commons-pool2:2.12.0", mavenRepo,
"redis.clients:jedis:5.1.0", mavenRepo,
"dev.dejvokep:boosted-yaml:1.3.1", mavenRepo,
"com.zaxxer:HikariCP:5.0.1", mavenRepo,
"org.mariadb.jdbc:mariadb-java-client:3.3.0", mavenRepo,
"com.mysql:mysql-connector-j:8.2.0", mavenRepo,
"commons-io:commons-io:2.14.0", mavenRepo,
"com.google.code.gson:gson:2.10.1", mavenRepo,
"com.h2database:h2:2.2.224", mavenRepo,
"org.mongodb:mongodb-driver-sync:4.11.1", mavenRepo,
"org.mongodb:mongodb-driver-core:4.11.1", mavenRepo,
"org.mongodb:bson:4.11.1", mavenRepo,
"org.xerial:sqlite-jdbc:3.43.2.2", mavenRepo,
"dev.jorel:commandapi-bukkit-shade:9.3.0", mavenRepo
);
}
public PacketManager getPacketManager() {
return packetManager;
}
}

View File

@@ -0,0 +1,333 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.paper.adventure;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.title.Title;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.manager.AdventureManager;
import net.momirealms.customnameplates.paper.mechanic.misc.PacketManager;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.setting.CNLocale;
import net.momirealms.customnameplates.paper.util.ReflectionUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class AdventureManagerImpl implements AdventureManager {
private final BukkitAudiences adventure;
private static AdventureManager instance;
private final CacheSystem cacheSystem;
public AdventureManagerImpl(CustomNameplatesPlugin plugin) {
this.adventure = BukkitAudiences.create(plugin);
this.cacheSystem = new CacheSystem();
instance = this;
}
public static AdventureManager getInstance() {
return instance;
}
public void close() {
if (adventure != null)
adventure.close();
}
@Override
public Object getIChatComponentFromMiniMessage(String text) {
return cacheSystem.getIChatFromCache(text);
}
@Override
public String stripTags(String text) {
return MiniMessage.miniMessage().stripTags(text);
}
@Override
public Component getComponentFromMiniMessage(String text) {
if (text == null) {
return Component.empty();
}
if (CNConfig.legacyColorSupport) {
return cacheSystem.getComponentFromCache(legacyToMiniMessage(text));
} else {
return cacheSystem.getComponentFromCache(text);
}
}
@Override
public void sendMessage(CommandSender sender, String s) {
if (s == null) return;
if (sender instanceof Player player) sendPlayerMessage(player, s);
else if (sender instanceof ConsoleCommandSender) sendConsoleMessage(s);
}
@Override
public void sendMessageWithPrefix(CommandSender sender, String s) {
if (s == null) return;
if (sender instanceof Player player) sendPlayerMessage(player, CNLocale.MSG_PREFIX + s);
else if (sender instanceof ConsoleCommandSender) sendConsoleMessage(CNLocale.MSG_PREFIX + s);
}
@Override
public void sendConsoleMessage(String s) {
if (s == null) return;
Audience au = adventure.sender(Bukkit.getConsoleSender());
au.sendMessage(getComponentFromMiniMessage(s));
}
@Override
public void sendPlayerMessage(Player player, String s) {
if (s == null) return;
Audience au = adventure.player(player);
au.sendMessage(getComponentFromMiniMessage(s));
}
@Override
public void sendTitle(Player player, String title, String subtitle, int in, int duration, int out) {
Audience au = adventure.player(player);
Title.Times times = Title.Times.times(Duration.ofMillis(in), Duration.ofMillis(duration), Duration.ofMillis(out));
au.showTitle(Title.title(getComponentFromMiniMessage(title), getComponentFromMiniMessage(subtitle), times));
}
@Override
public void sendTitle(Player player, Component title, Component subtitle, int in, int duration, int out) {
Audience au = adventure.player(player);
Title.Times times = Title.Times.times(Duration.ofMillis(in), Duration.ofMillis(duration), Duration.ofMillis(out));
au.showTitle(Title.title(title, subtitle, times));
}
@Override
public void sendActionbar(Player player, String text) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.SET_ACTION_BAR_TEXT);
packet.getModifier().write(0, getIChatComponent(componentToJson(getComponentFromMiniMessage(text).append(Component.score().name("np").objective("ab").build()))));
PacketManager.getInstance().send(player, packet);
}
@Override
public void sendActionbar(Player player, Component component) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.SET_ACTION_BAR_TEXT);
packet.getModifier().write(0, getIChatComponent(componentToJson(component)));
PacketManager.getInstance().send(player, packet);
}
@Override
public void sendSound(Player player, Sound.Source source, Key key, float volume, float pitch) {
Sound sound = Sound.sound(key, source, volume, pitch);
Audience au = adventure.player(player);
au.playSound(sound);
}
@Override
public void sendSound(Player player, Sound sound) {
Audience au = adventure.player(player);
au.playSound(sound);
}
@Override
public String legacyToMiniMessage(String legacy) {
StringBuilder stringBuilder = new StringBuilder();
char[] chars = legacy.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (!isColorCode(chars[i])) {
stringBuilder.append(chars[i]);
continue;
}
if (i + 1 >= chars.length) {
stringBuilder.append(chars[i]);
continue;
}
switch (chars[i+1]) {
case '0' -> stringBuilder.append("<black>");
case '1' -> stringBuilder.append("<dark_blue>");
case '2' -> stringBuilder.append("<dark_green>");
case '3' -> stringBuilder.append("<dark_aqua>");
case '4' -> stringBuilder.append("<dark_red>");
case '5' -> stringBuilder.append("<dark_purple>");
case '6' -> stringBuilder.append("<gold>");
case '7' -> stringBuilder.append("<gray>");
case '8' -> stringBuilder.append("<dark_gray>");
case '9' -> stringBuilder.append("<blue>");
case 'a' -> stringBuilder.append("<green>");
case 'b' -> stringBuilder.append("<aqua>");
case 'c' -> stringBuilder.append("<red>");
case 'd' -> stringBuilder.append("<light_purple>");
case 'e' -> stringBuilder.append("<yellow>");
case 'f' -> stringBuilder.append("<white>");
case 'r' -> stringBuilder.append("<r><!i>");
case 'l' -> stringBuilder.append("<b>");
case 'm' -> stringBuilder.append("<s>");
case 'o' -> stringBuilder.append("<i>");
case 'n' -> stringBuilder.append("<u>");
case 'k' -> stringBuilder.append("<o>");
case 'x' -> {
if (i + 13 >= chars.length
|| !isColorCode(chars[i+2])
|| !isColorCode(chars[i+4])
|| !isColorCode(chars[i+6])
|| !isColorCode(chars[i+8])
|| !isColorCode(chars[i+10])
|| !isColorCode(chars[i+12])) {
stringBuilder.append(chars[i]);
continue;
}
stringBuilder
.append("<#")
.append(chars[i+3])
.append(chars[i+5])
.append(chars[i+7])
.append(chars[i+9])
.append(chars[i+11])
.append(chars[i+13])
.append(">");
i += 12;
}
default -> {
stringBuilder.append(chars[i]);
continue;
}
}
i++;
}
return stringBuilder.toString();
}
@Override
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean isColorCode(char c) {
return c == '§' || c == '&';
}
@Override
public String componentToLegacy(Component component) {
return LegacyComponentSerializer.legacySection().serialize(component);
}
@Override
public String componentToJson(Component component) {
return GsonComponentSerializer.gson().serialize(component);
}
@Override
public Object shadedToOriginal(Component component) {
Object cp;
try {
cp = ReflectionUtils.gsonDeserializeMethod.invoke(ReflectionUtils.gsonInstance, GsonComponentSerializer.gson().serialize(component));
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
return cp;
}
@Override
public String getMiniMessageFormat(Component component) {
return MiniMessage.miniMessage().serialize(component);
}
@Override
public Object getIChatComponent(String json) {
try {
return ReflectionUtils.iChatComponentMethod.invoke(null, json);
} catch (InvocationTargetException | IllegalAccessException exception) {
exception.printStackTrace();
return ReflectionUtils.emptyComponent;
}
}
public class CacheSystem {
private final LoadingCache<String, Object> miniMessageToIChatComponentCache;
private final LoadingCache<String, Component> miniMessageToComponentCache;
public CacheSystem() {
miniMessageToIChatComponentCache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(
new CacheLoader<>() {
@NotNull
@Override
public Object load(@NotNull String text) {
return fetchIChatData(text);
}
});
miniMessageToComponentCache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(
new CacheLoader<>() {
@NotNull
@Override
public Component load(@NotNull String text) {
return fetchComponent(text);
}
});
}
@NotNull
private Object fetchIChatData(String text) {
Component component = getComponentFromMiniMessage(text);
return getIChatComponent(GsonComponentSerializer.gson().serialize(component));
}
@NotNull
private Component fetchComponent(String text) {
return getComponentFromMiniMessage(text);
}
public Object getIChatFromCache(String text) {
try {
return miniMessageToIChatComponentCache.get(text);
} catch (ExecutionException e) {
e.printStackTrace();
return ReflectionUtils.emptyComponent;
}
}
public Component getComponentFromCache(String text) {
try {
return miniMessageToComponentCache.get(text);
} catch (ExecutionException e) {
e.printStackTrace();
return Component.empty();
}
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.paper.command;
import dev.jorel.commandapi.CommandAPI;
import dev.jorel.commandapi.CommandAPIBukkitConfig;
import dev.jorel.commandapi.CommandAPICommand;
import dev.jorel.commandapi.arguments.ArgumentSuggestions;
import dev.jorel.commandapi.arguments.StringArgument;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import net.momirealms.customnameplates.paper.adventure.AdventureManagerImpl;
import net.momirealms.customnameplates.paper.setting.CNLocale;
import org.bukkit.entity.Player;
public class CommandManager {
private final CustomNameplatesPluginImpl plugin;
public CommandManager(CustomNameplatesPluginImpl plugin) {
this.plugin = plugin;
if (!CommandAPI.isLoaded())
CommandAPI.onLoad(new CommandAPIBukkitConfig(plugin).silentLogs(true));
}
public void load() {
new CommandAPICommand("customnameplates")
.withAliases("nameplates", "cnameplates")
.withPermission("customnameplates.admin")
.withSubcommands(
getReloadCommand(),
getAboutCommand(),
getEquipCommand(),
getUnEquipCommand()
)
.register();
}
private CommandAPICommand getEquipCommand() {
return new CommandAPICommand("equip")
.withArguments(new StringArgument("nameplate").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> plugin.getNameplateManager().getAvailableNameplates((Player) commandSenderSuggestionInfo.sender()).toArray(new String[0]))))
.executesPlayer((player, args) -> {
String nameplate = (String) args.get("nameplate");
if (!plugin.getNameplateManager().hasNameplate(player, nameplate)) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CNLocale.MSG_NAMEPLATE_NOT_AVAILABLE);
return;
}
if (!plugin.getNameplateManager().equipNameplate(player, nameplate)) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CNLocale.MSG_NAMEPLATE_NOT_EXISTS);
return;
}
AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CNLocale.MSG_EQUIP_NAMEPLATE);
});
}
private CommandAPICommand getUnEquipCommand() {
return new CommandAPICommand("unequip")
.executesPlayer((player, args) -> {
plugin.getNameplateManager().unEquipNameplate(player);
AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CNLocale.MSG_UNEQUIP_NAMEPLATE);
});
}
private CommandAPICommand getReloadCommand() {
return new CommandAPICommand("reload")
.executes((sender, args) -> {
long time = System.currentTimeMillis();
plugin.reload(true);
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, CNLocale.MSG_RELOAD.replace("{time}", String.valueOf(System.currentTimeMillis()-time)));
});
}
private CommandAPICommand getAboutCommand() {
return new CommandAPICommand("about").executes((sender, args) -> {
AdventureManagerImpl.getInstance().sendMessage(sender, "<#3CB371>⚓ CustomNameplates <gray>- <#98FB98>" + CustomNameplatesPlugin.getInstance().getVersionManager().getPluginVersion());
AdventureManagerImpl.getInstance().sendMessage(sender, "<#7FFFAA>A plugin that provides adjustable images for texts");
AdventureManagerImpl.getInstance().sendMessage(sender, "<#DA70D6>\uD83E\uDDEA Author: <#FFC0CB>XiaoMoMi");
AdventureManagerImpl.getInstance().sendMessage(sender, "<#FF7F50>\uD83D\uDD25 Contributors: <#FFA07A>TopOrigin<white>");
AdventureManagerImpl.getInstance().sendMessage(sender, "<#FFD700>⭐ <click:open_url:https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates>Document</click> <#A9A9A9>| <#FAFAD2>⛏ <click:open_url:https://github.com/Xiao-MoMi/Custom-Nameplates>Github</click> <#A9A9A9>| <#48D1CC>\uD83D\uDD14 <click:open_url:https://polymart.org/resource/customnameplates.2543>Polymart</click>");
});
}
}

View File

@@ -23,11 +23,13 @@
* SOFTWARE.
*/
package net.momirealms.customnameplates.helper;
package net.momirealms.customnameplates.paper.helper;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import net.momirealms.customnameplates.CustomNameplates;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.CustomNameplatesPluginImpl;
import java.io.File;
import java.io.InputStream;
@@ -42,11 +44,10 @@ import java.util.StringJoiner;
* Resolves {@link MavenLibrary} annotations for a class, and loads the dependency
* into the classloader.
*/
@NonnullByDefault
public final class LibraryLoader {
@SuppressWarnings("Guava")
private static final Supplier<URLClassLoaderAccess> URL_INJECTOR = Suppliers.memoize(() -> URLClassLoaderAccess.create((URLClassLoader) CustomNameplates.getInstance().getClass().getClassLoader()));
private static final Supplier<URLClassLoaderAccess> URL_INJECTOR = Suppliers.memoize(() -> URLClassLoaderAccess.create((URLClassLoader) CustomNameplatesPluginImpl.getInstance().getClass().getClassLoader()));
/**
* Resolves all {@link MavenLibrary} annotations on the given object.
@@ -73,31 +74,38 @@ public final class LibraryLoader {
load(new Dependency(groupId, artifactId, version, repoUrl));
}
public static void load(Dependency d) {
//Log.info(String.startFormat("Loading dependency %s:%s:%s from %s", d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getRepoUrl()));
String name = d.getArtifactId() + "-" + d.getVersion();
File saveLocation = new File(getLibFolder(d), name + ".jar");
if (!saveLocation.exists()) {
try {
Log.info("Dependency '" + name + "' is not already in the libraries folder. Attempting to download...");
URL url = d.getUrl();
try (InputStream is = url.openStream()) {
Files.copy(is, saveLocation.toPath());
Log.info("Dependency '" + name + "' successfully downloaded.");
public static void loadDependencies(String... libs) {
if (libs == null || libs.length % 2 != 0)
return;
for (int i = 0; i < libs.length; i+=2) {
String[] split = libs[i].split(":");
load(new Dependency(
split[0],
split[1],
split[2],
libs[i+1]
));
}
}
public static void load(Dependency d) {
// LogUtils.info(String.format("Loading dependency %s:%s:%s", d.groupId, d.artifactId, d.version));
String name = d.artifactId() + "-" + d.version();
File saveLocation = new File(getLibFolder(d), name + ".jar");
if (!saveLocation.exists()) {
try {
LogUtils.info("Dependency '" + name + "' is not already in the libraries folder. Attempting to download...");
URL url = d.getUrl();
try (InputStream is = url.openStream()) {
Files.copy(is, saveLocation.toPath());
LogUtils.info("Dependency '" + name + "' successfully downloaded.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (!saveLocation.exists()) {
if (!saveLocation.exists())
throw new RuntimeException("Unable to download dependency: " + d);
}
try {
URL_INJECTOR.get().addURL(saveLocation.toURI().toURL());
} catch (Exception e) {
@@ -105,12 +113,13 @@ public final class LibraryLoader {
}
}
@SuppressWarnings("all")
private static File getLibFolder(Dependency dependency) {
File pluginDataFolder = CustomNameplates.getInstance().getDataFolder();
File pluginDataFolder = CustomNameplatesPlugin.getInstance().getDataFolder();
File serverDir = pluginDataFolder.getParentFile().getParentFile();
File helperDir = new File(serverDir, "libraries");
String[] split = dependency.getGroupId().split("\\.");
String[] split = dependency.groupId().split("\\.");
File jarDir;
StringJoiner stringJoiner = new StringJoiner(File.separator);
for (String str : split) {
@@ -121,13 +130,7 @@ public final class LibraryLoader {
return jarDir;
}
@NonnullByDefault
public static final class Dependency {
private final String groupId;
private final String artifactId;
private final String version;
private final String repoUrl;
public record Dependency(String groupId, String artifactId, String version, String repoUrl) {
public Dependency(String groupId, String artifactId, String version, String repoUrl) {
this.groupId = Objects.requireNonNull(groupId, "groupId");
this.artifactId = Objects.requireNonNull(artifactId, "artifactId");
@@ -135,22 +138,6 @@ public final class LibraryLoader {
this.repoUrl = Objects.requireNonNull(repoUrl, "repoUrl");
}
public String getGroupId() {
return this.groupId;
}
public String getArtifactId() {
return this.artifactId;
}
public String getVersion() {
return this.version;
}
public String getRepoUrl() {
return this.repoUrl;
}
public URL getUrl() throws MalformedURLException {
String repo = this.repoUrl;
if (!repo.endsWith("/")) {
@@ -165,32 +152,31 @@ public final class LibraryLoader {
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Dependency)) return false;
final Dependency other = (Dependency) o;
return this.getGroupId().equals(other.getGroupId()) &&
this.getArtifactId().equals(other.getArtifactId()) &&
this.getVersion().equals(other.getVersion()) &&
this.getRepoUrl().equals(other.getRepoUrl());
if (!(o instanceof Dependency other)) return false;
return this.groupId().equals(other.groupId()) &&
this.artifactId().equals(other.artifactId()) &&
this.version().equals(other.version()) &&
this.repoUrl().equals(other.repoUrl());
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.getGroupId().hashCode();
result = result * PRIME + this.getArtifactId().hashCode();
result = result * PRIME + this.getVersion().hashCode();
result = result * PRIME + this.getRepoUrl().hashCode();
result = result * PRIME + this.groupId().hashCode();
result = result * PRIME + this.artifactId().hashCode();
result = result * PRIME + this.version().hashCode();
result = result * PRIME + this.repoUrl().hashCode();
return result;
}
@Override
public String toString() {
return "LibraryLoader.Dependency(" +
"groupId=" + this.getGroupId() + ", " +
"artifactId=" + this.getArtifactId() + ", " +
"version=" + this.getVersion() + ", " +
"repoUrl=" + this.getRepoUrl() + ")";
"groupId=" + this.groupId() + ", " +
"artifactId=" + this.artifactId() + ", " +
"version=" + this.version() + ", " +
"repoUrl=" + this.repoUrl() + ")";
}
}
}

View File

@@ -23,9 +23,10 @@
* SOFTWARE.
*/
package net.momirealms.customnameplates.helper;
package net.momirealms.customnameplates.paper.helper;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.lang.annotation.*;
/**
@@ -36,7 +37,7 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface MavenLibraries {
@Nonnull
@NotNull
MavenLibrary[] value() default {};
}

View File

@@ -23,9 +23,10 @@
* SOFTWARE.
*/
package net.momirealms.customnameplates.helper;
package net.momirealms.customnameplates.paper.helper;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.lang.annotation.*;
/**
@@ -42,7 +43,7 @@ public @interface MavenLibrary {
*
* @return the group id of the library
*/
@Nonnull
@NotNull
String groupId();
/**
@@ -50,7 +51,7 @@ public @interface MavenLibrary {
*
* @return the artifact id of the library
*/
@Nonnull
@NotNull
String artifactId();
/**
@@ -58,7 +59,7 @@ public @interface MavenLibrary {
*
* @return the version of the library
*/
@Nonnull
@NotNull
String version();
/**
@@ -66,7 +67,7 @@ public @interface MavenLibrary {
*
* @return the repo where the library can be obtained from
*/
@Nonnull
@NotNull
Repository repo() default @Repository(url = "https://repo1.maven.org/maven2");
}

View File

@@ -23,9 +23,8 @@
* SOFTWARE.
*/
package net.momirealms.customnameplates.helper;
package net.momirealms.customnameplates.paper.helper;
import javax.annotation.Nonnull;
import java.lang.annotation.*;
/**
@@ -41,7 +40,6 @@ public @interface Repository {
*
* @return the base url of the repository
*/
@Nonnull
String url();
}

View File

@@ -23,9 +23,10 @@
* SOFTWARE.
*/
package net.momirealms.customnameplates.helper;
package net.momirealms.customnameplates.paper.helper;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
@@ -62,7 +63,7 @@ public abstract class URLClassLoaderAccess {
*
* @param url the URL to add
*/
public abstract void addURL(@Nonnull URL url);
public abstract void addURL(@NotNull URL url);
/**
* Accesses using sun.misc.Unsafe, supported on Java 9+.
@@ -116,7 +117,7 @@ public abstract class URLClassLoaderAccess {
}
@Override
public void addURL(@Nonnull URL url) {
public void addURL(@NotNull URL url) {
this.unopenedURLs.add(url);
this.pathURLs.add(url);
}
@@ -130,7 +131,7 @@ public abstract class URLClassLoaderAccess {
}
@Override
public void addURL(@Nonnull URL url) {
public void addURL(@NotNull URL url) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,79 @@
package net.momirealms.customnameplates.paper.mechanic.actionbar;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.paper.mechanic.bossbar.BarColor;
import net.momirealms.customnameplates.paper.mechanic.bossbar.Overlay;
import net.momirealms.customnameplates.paper.mechanic.misc.TimeLimitText;
public class ActionBarConfig {
private int checkFrequency;
private Requirement[] requirements;
private TimeLimitText[] textDisplayOrder;
private ActionBarConfig() {
checkFrequency = 1;
requirements = new Requirement[0];
textDisplayOrder = new TimeLimitText[0];
}
public ActionBarConfig(
Overlay overlay,
BarColor barColor,
int checkFrequency,
Requirement[] requirements,
TimeLimitText[] textDisplayOrder
) {
this.checkFrequency = checkFrequency;
this.requirements = requirements;
this.textDisplayOrder = textDisplayOrder;
}
public int getCheckFrequency() {
return checkFrequency;
}
public Requirement[] getRequirements() {
return requirements;
}
public TimeLimitText[] getTextDisplayOrder() {
return textDisplayOrder;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final ActionBarConfig config;
public Builder() {
this.config = new ActionBarConfig();
}
public static Builder of() {
return new Builder();
}
public Builder checkFrequency(int checkFrequency) {
config.checkFrequency = checkFrequency;
return this;
}
public Builder requirement(Requirement[] requirements) {
config.requirements = requirements;
return this;
}
public Builder displayOrder(TimeLimitText[] textDisplayOrder) {
config.textDisplayOrder = textDisplayOrder;
return this;
}
public ActionBarConfig build() {
return config;
}
}
}

View File

@@ -0,0 +1,219 @@
package net.momirealms.customnameplates.paper.mechanic.actionbar;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.manager.ActionBarManager;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.adventure.AdventureManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.actionbar.listener.ActionBarListener;
import net.momirealms.customnameplates.paper.mechanic.actionbar.listener.ChatMessageListener;
import net.momirealms.customnameplates.paper.mechanic.actionbar.listener.SystemChatListener;
import net.momirealms.customnameplates.paper.mechanic.misc.DisplayController;
import net.momirealms.customnameplates.paper.setting.CNConfig;
import net.momirealms.customnameplates.paper.util.ConfigUtils;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class ActionBarManagerImpl implements ActionBarManager, Listener {
private final ConcurrentHashMap<UUID, ActionBarReceiver> receiverMap;
private final CustomNameplatesPlugin plugin;
private final ActionBarListener actionBarListener;
private ActionBarConfig config;
private ChatMessageListener chatMessageListener;
private SystemChatListener systemChatListener;
public ActionBarManagerImpl(CustomNameplatesPlugin plugin) {
this.receiverMap = new ConcurrentHashMap<>();
this.plugin = plugin;
this.actionBarListener = new ActionBarListener(this);
if (plugin.getVersionManager().isVersionNewerThan1_19()) {
this.systemChatListener = new SystemChatListener(this);
} else {
this.chatMessageListener = new ChatMessageListener(this);
}
}
public void load() {
if (!CNConfig.actionBarModule) return;
this.loadConfigs();
for (Player player : Bukkit.getOnlinePlayers()) {
createActionBarFor(player);
}
Bukkit.getPluginManager().registerEvents(this, plugin);
if (actionBarListener != null) ProtocolLibrary.getProtocolManager().addPacketListener(actionBarListener);
if (systemChatListener != null) ProtocolLibrary.getProtocolManager().addPacketListener(systemChatListener);
if (chatMessageListener != null) ProtocolLibrary.getProtocolManager().addPacketListener(chatMessageListener);
}
public void unload() {
for (ActionBarReceiver receiver : receiverMap.values()) {
receiver.cancelTask();
receiver.destroy();
}
receiverMap.clear();
HandlerList.unregisterAll(this);
if (actionBarListener != null) ProtocolLibrary.getProtocolManager().removePacketListener(actionBarListener);
if (systemChatListener != null) ProtocolLibrary.getProtocolManager().removePacketListener(systemChatListener);
if (chatMessageListener != null) ProtocolLibrary.getProtocolManager().removePacketListener(chatMessageListener);
}
public void reload() {
unload();
load();
}
private void loadConfigs() {
YamlConfiguration config = plugin.getConfig("configs" + File.separator + "actionbar.yml");
for (Map.Entry<String, Object> barEntry : config.getValues(false).entrySet()) {
if (!(barEntry.getValue() instanceof ConfigurationSection section))
return;
this.config = ActionBarConfig.Builder.of()
.checkFrequency(section.getInt("check-frequency", 10))
.requirement(plugin.getRequirementManager().getRequirements(section.getConfigurationSection("conditions")))
.displayOrder(ConfigUtils.getTimeLimitTexts(section.getConfigurationSection("text-display-order")))
.build();
}
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
if (CNConfig.sendDelay == 0) {
createActionBarFor(player);
return;
}
this.plugin.getScheduler().runTaskAsyncLater(() -> {
createActionBarFor(player);
}, CNConfig.sendDelay * 50L, TimeUnit.MILLISECONDS);
}
private void createActionBarFor(Player player) {
if (player == null || !player.isOnline()) {
return;
}
ActionBarReceiver receiver = new ActionBarReceiver(plugin, player, new DisplayController(
player, config.getCheckFrequency(), config.getRequirements(), config.getTextDisplayOrder()
));
receiver.arrangeTask();
this.putReceiverToMap(player.getUniqueId(), receiver);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
ActionBarReceiver receiver = receiverMap.remove(event.getPlayer().getUniqueId());
if (receiver != null) {
receiver.cancelTask();
}
}
private void putReceiverToMap(UUID uuid, ActionBarReceiver actionBarReceiver) {
ActionBarReceiver previous = this.receiverMap.put(uuid, actionBarReceiver);
if (previous != null) {
LogUtils.warn("Unexpected error: Duplicated actionbar created");
previous.cancelTask();
}
}
private ActionBarReceiver getReceiver(UUID uuid) {
return this.receiverMap.get(uuid);
}
// 1.19+
public void onReceiveSystemChatPacket(PacketEvent event) {
PacketContainer packet = event.getPacket();
Boolean overlay = packet.getBooleans().readSafely(0);
if (overlay != null && overlay) {
ActionBarReceiver receiver = getReceiver(event.getPlayer().getUniqueId());
if (receiver != null) {
event.setCancelled(true);
String json = packet.getStrings().readSafely(0);
if (json != null && !json.equals("")) {
Component component = GsonComponentSerializer.gson().deserialize(json);
if (component instanceof TranslatableComponent) {
// We can't get TranslatableComponent's width :(
return;
}
receiver.setOtherPluginText(AdventureManagerImpl.getInstance().getMiniMessageFormat(component), System.currentTimeMillis());
}
}
}
}
// lower version
public void onReceiveChatMessagePacket(PacketEvent event) {
PacketContainer packet = event.getPacket();
EnumWrappers.ChatType type = packet.getChatTypes().readSafely(0);
if (type == EnumWrappers.ChatType.GAME_INFO) {
ActionBarReceiver receiver = getReceiver(event.getPlayer().getUniqueId());
if (receiver != null) {
event.setCancelled(true);
WrappedChatComponent wrappedChatComponent = packet.getChatComponents().read(0);
if (wrappedChatComponent != null) {
String json = wrappedChatComponent.getJson();
Component component = GsonComponentSerializer.gson().deserialize(json);
if (component instanceof TranslatableComponent) {
// We can't get TranslatableComponent's width :(
return;
}
receiver.setOtherPluginText(AdventureManagerImpl.getInstance().getMiniMessageFormat(component), System.currentTimeMillis());
}
}
}
}
public void onReceiveActionBarPacket(PacketEvent event) {
PacketContainer packet = event.getPacket();
WrappedChatComponent wrappedChatComponent = packet.getChatComponents().read(0);
if (wrappedChatComponent != null) {
ActionBarReceiver receiver = getReceiver(event.getPlayer().getUniqueId());
if (receiver != null) {
String strJson = wrappedChatComponent.getJson();
// for better performance
if (strJson.contains("\"name\":\"np\",\"objective\":\"ab\"")) {
return;
}
event.setCancelled(true);
receiver.setOtherPluginText(
AdventureManagerImpl.getInstance().getMiniMessageFormat(
GsonComponentSerializer.gson().deserialize(strJson)
), System.currentTimeMillis()
);
}
}
}
@NotNull
@Override
public String getOtherPluginActionBar(Player player) {
ActionBarReceiver receiver = getReceiver(player.getUniqueId());
if (receiver != null) {
return receiver.getOtherPluginText();
}
return "";
}
}

View File

@@ -0,0 +1,102 @@
package net.momirealms.customnameplates.paper.mechanic.actionbar;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.scheduler.CancellableTask;
import net.momirealms.customnameplates.api.util.LogUtils;
import net.momirealms.customnameplates.paper.adventure.AdventureManagerImpl;
import net.momirealms.customnameplates.paper.mechanic.misc.DisplayController;
import org.bukkit.entity.Player;
import java.util.concurrent.TimeUnit;
public class ActionBarReceiver {
private final CustomNameplatesPlugin plugin;
private final Player player;
private CancellableTask actionBarTask;
private final DisplayController controller;
private long lastUpdateTime;
private String otherPluginText;
private long expireTime;
public ActionBarReceiver(CustomNameplatesPlugin plugin, Player player, DisplayController controller) {
this.plugin = plugin;
this.player = player;
this.controller = controller;
this.otherPluginText = "";
}
public void timer() {
if (System.currentTimeMillis() > expireTime) {
this.otherPluginText = "";
}
Condition condition = new Condition(player);
switch (controller.stateCheck(condition)) {
case KEEP -> {
if (!controller.isShown()) {
return;
}
long current = System.currentTimeMillis();
if (controller.updateText(condition) || shouldSendBeatPack(current)) {
AdventureManagerImpl.getInstance().sendActionbar(player, controller.getLatestContent());
lastUpdateTime = current;
}
}
case UPDATE -> {
if (controller.isShown()) {
controller.initialize();
AdventureManagerImpl.getInstance().sendActionbar(player, controller.getLatestContent());
} else {
AdventureManagerImpl.getInstance().sendActionbar(player, "");
}
}
}
}
public void arrangeTask() {
if (this.actionBarTask != null && !this.actionBarTask.isCancelled()) {
LogUtils.warn("There's already an ActionBar task running");
return;
}
this.actionBarTask = this.plugin.getScheduler().runTaskAsyncTimer(() -> {
try {
timer();
} catch (Exception e) {
LogUtils.severe(
"Error occurred when sending ActionBars. " +
"This might not be a bug in CustomNameplates. Please report " +
"to the Plugin on the top of the following " +
"stack trace."
);
e.printStackTrace();
}
}, 50, 50, TimeUnit.MILLISECONDS);
}
public void cancelTask() {
if (this.actionBarTask == null) {
LogUtils.warn("ActionBar task has been already cancelled");
return;
}
this.actionBarTask.cancel();
this.actionBarTask = null;
}
public boolean shouldSendBeatPack(long current) {
return current - lastUpdateTime > 1700;
}
public void setOtherPluginText(String text, long current) {
this.otherPluginText = text;
this.expireTime = current + 3000;
}
public String getOtherPluginText() {
return otherPluginText;
}
public void destroy() {
AdventureManagerImpl.getInstance().sendActionbar(player, "");
}
}

View File

@@ -15,21 +15,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.listener.packet;
package net.momirealms.customnameplates.paper.mechanic.actionbar.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import net.momirealms.customnameplates.CustomNameplates;
import net.momirealms.customnameplates.manager.ActionBarManager;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.mechanic.actionbar.ActionBarManagerImpl;
public class ActionBarListener extends PacketAdapter {
private final ActionBarManager actionBarManager;
private final ActionBarManagerImpl actionBarManager;
public ActionBarListener(ActionBarManager actionBarManager) {
super(CustomNameplates.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.SET_ACTION_BAR_TEXT);
public ActionBarListener(ActionBarManagerImpl actionBarManager) {
super(CustomNameplatesPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.SET_ACTION_BAR_TEXT);
this.actionBarManager = actionBarManager;
}

View File

@@ -15,21 +15,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.listener.packet;
package net.momirealms.customnameplates.paper.mechanic.actionbar.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import net.momirealms.customnameplates.CustomNameplates;
import net.momirealms.customnameplates.manager.ActionBarManager;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.paper.mechanic.actionbar.ActionBarManagerImpl;
public class ChatMessageListener extends PacketAdapter {
private final ActionBarManager actionBarManager;
private final ActionBarManagerImpl actionBarManager;
public ChatMessageListener(ActionBarManager actionBarManager) {
super(CustomNameplates.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.CHAT);
public ChatMessageListener(ActionBarManagerImpl actionBarManager) {
super(CustomNameplatesPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.CHAT);
this.actionBarManager = actionBarManager;
}

Some files were not shown because too many files have changed in this diff Show More