diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 341bd4aa..b94f7f2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ '11', '17' ] + java: [ '21' ] name: Build with Java ${{ matrix.java }} steps: - name: Checkout Git repository @@ -70,11 +70,11 @@ jobs: key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - - name: Setup JDK 17 + - name: Setup JDK 21 uses: actions/setup-java@v4 with: distribution: adopt - java-version: 17 + java-version: 21 - name: Build with Gradle run: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 15e030a4..32b7d20f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,18 +20,18 @@ jobs: fetch-depth: 0 - name: Restore Gradle cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} restore-keys: | ${{ runner.os }}-gradle- - - name: Setup JDK 17 - uses: actions/setup-java@v3 + - name: Setup JDK 21 + uses: actions/setup-java@v4 with: distribution: adopt - java-version: 17 + java-version: 21 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 723953e4..777f130e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,18 +14,18 @@ jobs: fetch-depth: 0 - name: Restore Gradle cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} restore-keys: | ${{ runner.os }}-gradle- - - name: Setup JDK 17 - uses: actions/setup-java@v2 + - name: Setup JDK 21 + uses: actions/setup-java@v4 with: distribution: adopt - java-version: 17 + java-version: 21 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb2cfd55..1ad3b932 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,5 +43,5 @@ Maybe the usage of [`git rebase`](http://learn.github.com/p/rebasing.html) could Requirements ------------ -- Java 11+ +- Java 21+ - Gradle 8+ diff --git a/README.md b/README.md index 94ae3484..34a1c230 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@
@@ -52,7 +52,7 @@ Works with Bukkit/Spigot 1.8 to 1.20!
|-----------|------------------------------|-------------|----------------------------------------------------------------------------------------------|
| 2.2.2 | 1.8 to 1.17 | Stable | [Click here](https://www.spigotmc.org/resources/endercontainers.4750/) |
| 2.2.3-dev | 1.8 to 1.20 | Beta | [Click here](https://utarwyn.fr/projects/EnderContainers/EnderContainers-2.2.3-SNAPSHOT.jar) |
-| 2.3.0-dev | 1.8 to 1.20 | Development | [Click here](https://utarwyn.fr/projects/EnderContainers/EnderContainers-2.3.0-SNAPSHOT.jar) |
+| 2.3.0-dev | 1.8 to 1.21 | Development | [Click here](https://utarwyn.fr/projects/EnderContainers/EnderContainers-2.3.0-SNAPSHOT.jar) |
## Technical Features
diff --git a/buildSrc/src/main/groovy/fr.utarwyn.java-conventions.gradle b/buildSrc/src/main/groovy/fr.utarwyn.java-conventions.gradle
index d8245a36..5b143c2c 100644
--- a/buildSrc/src/main/groovy/fr.utarwyn.java-conventions.gradle
+++ b/buildSrc/src/main/groovy/fr.utarwyn.java-conventions.gradle
@@ -23,13 +23,13 @@ configurations {
}
dependencies {
- compileOnly 'org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT'
+ compileOnly 'org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT' // cannot upgrade due to Inventory errors
testImplementation platform('org.junit:junit-bom:5.10.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
- testImplementation 'org.mockito:mockito-core:4.11.0' // cannot upgrade to 5+ because of Java 8 compatibility
- testImplementation 'org.mockito:mockito-junit-jupiter:4.11.0'
- testImplementation 'org.assertj:assertj-core:3.24.2'
+ testImplementation 'org.mockito:mockito-core:5.15.2'
+ testImplementation 'org.mockito:mockito-junit-jupiter:5.15.2'
+ testImplementation 'org.assertj:assertj-core:3.27.3'
}
publishing {
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ArmorStandAdapter.java b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ArmorStandAdapter.java
new file mode 100644
index 00000000..a3a2b4c7
--- /dev/null
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ArmorStandAdapter.java
@@ -0,0 +1,37 @@
+package fr.utarwyn.endercontainers.compatibility;
+
+import fr.utarwyn.endercontainers.hologram.HologramException;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+/**
+ * Adapter interface for managing armor stands as holographic displays.
+ * This interface provides methods to spawn and destroy armor stands for specific players,
+ * typically used for version-specific implementations.
+ *
+ * @author Utarwyn
+ * @since 2.3.0
+ */
+public interface ArmorStandAdapter {
+
+ /**
+ * Spawns an armor stand with text at a specific location for a player.
+ *
+ * @param plugin the plugin instance
+ * @param observer the player who will see the armor stand
+ * @param location the location where to spawn the armor stand
+ * @param text the text to display above the armor stand
+ * @return the entity ID of the spawned armor stand
+ */
+ int spawnArmorStandFor(Plugin plugin, Player observer, Location location, String text) throws HologramException;
+
+ /**
+ * Destroys an armor stand for a specific player.
+ *
+ * @param observer the player who can see the armor stand
+ * @param entityId the entity ID of the armor stand to destroy
+ */
+ void destroyArmorStandFor(Player observer, int entityId) throws HologramException;
+
+}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/CompatibilityHelper.java b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/CompatibilityHelper.java
index cf8bc136..9b3fbc49 100644
--- a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/CompatibilityHelper.java
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/CompatibilityHelper.java
@@ -1,6 +1,8 @@
package fr.utarwyn.endercontainers.compatibility;
import com.google.common.base.Preconditions;
+import fr.utarwyn.endercontainers.compatibility.bukkit.BukkitArmorStandAdapter;
+import fr.utarwyn.endercontainers.compatibility.nms.NMSArmorStandAdapter;
import org.bukkit.Material;
import org.bukkit.Sound;
@@ -63,4 +65,15 @@ public static Sound searchSound(String... names) throws IllegalArgumentException
});
}
+ /**
+ * Creates a new armor stand adapter instance based on the server version.
+ *
+ * @return a new armor stand adapter instance
+ */
+ public static ArmorStandAdapter createArmorStandAdapter() {
+ return ServerVersion.isNewerThan(ServerVersion.V1_18)
+ ? new BukkitArmorStandAdapter()
+ : new NMSArmorStandAdapter();
+ }
+
}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ServerVersion.java b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ServerVersion.java
index f33edc45..ab70c46f 100644
--- a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ServerVersion.java
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/ServerVersion.java
@@ -10,6 +10,7 @@
*/
public enum ServerVersion {
+ NEWER,
V1_20,
V1_19_R3,
V1_19_R2,
@@ -35,10 +36,15 @@ public enum ServerVersion {
String path = Bukkit.getServer().getClass().getPackage().getName();
BUKKIT_VERSION = path.substring(path.lastIndexOf('.') + 1);
- for (ServerVersion version : values()) {
- if (BUKKIT_VERSION.toUpperCase().startsWith(version.name())) {
- currentVersion = version;
- break;
+ // starting from 1.20.5, version is no more in package name
+ if ("craftbukkit".equals(BUKKIT_VERSION)) {
+ currentVersion = NEWER;
+ } else {
+ for (ServerVersion version : values()) {
+ if (BUKKIT_VERSION.toUpperCase().startsWith(version.name())) {
+ currentVersion = version;
+ break;
+ }
}
}
}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/bukkit/BukkitArmorStandAdapter.java b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/bukkit/BukkitArmorStandAdapter.java
new file mode 100644
index 00000000..7bcbba0b
--- /dev/null
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/bukkit/BukkitArmorStandAdapter.java
@@ -0,0 +1,40 @@
+package fr.utarwyn.endercontainers.compatibility.bukkit;
+
+import fr.utarwyn.endercontainers.compatibility.ArmorStandAdapter;
+import org.bukkit.Location;
+import org.bukkit.entity.ArmorStand;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+import java.util.Objects;
+
+public class BukkitArmorStandAdapter implements ArmorStandAdapter {
+
+ @Override
+ public int spawnArmorStandFor(Plugin plugin, Player observer, Location location, String text) {
+ ArmorStand armorStand = (ArmorStand) Objects.requireNonNull(location.getWorld()).spawnEntity(location.add(0, 2, 0), EntityType.ARMOR_STAND);
+
+ armorStand.setInvisible(true);
+ armorStand.setCustomName(text);
+ armorStand.setCustomNameVisible(true);
+ armorStand.setGravity(false);
+ armorStand.setInvulnerable(true);
+ armorStand.setMarker(true);
+
+ observer.showEntity(plugin, armorStand);
+
+ return armorStand.getEntityId();
+ }
+
+ @Override
+ public void destroyArmorStandFor(Player observer, int entityId) {
+ observer.getWorld().getEntities().stream()
+ .filter(e -> e.getEntityId() == entityId)
+ .findFirst()
+ .ifPresent(Entity::remove);
+
+ }
+
+}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSArmorStandAdapter.java b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSArmorStandAdapter.java
new file mode 100644
index 00000000..93ba5752
--- /dev/null
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSArmorStandAdapter.java
@@ -0,0 +1,40 @@
+package fr.utarwyn.endercontainers.compatibility.nms;
+
+import fr.utarwyn.endercontainers.compatibility.ArmorStandAdapter;
+import fr.utarwyn.endercontainers.hologram.HologramException;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+/**
+ * Adapter for managing armor stands as holographic displays.
+ * This adapter provides methods to spawn and destroy armor stands for specific players.
+ * This adapter is used for NMS implementations prior MC 1.19.
+ *
+ * @author Utarwyn
+ * @since 2.3.0
+ */
+public class NMSArmorStandAdapter implements ArmorStandAdapter {
+
+ @Override
+ public int spawnArmorStandFor(Plugin plugin, Player observer, Location location, String text) throws HologramException {
+ try {
+ return NMSHologramUtil.get().spawnHologram(location, text, observer);
+ } catch (ReflectiveOperationException cause) {
+ throw new HologramException("cannot spawn hologram entity", cause);
+ }
+ }
+
+ @Override
+ public void destroyArmorStandFor(Player observer, int entityId) throws HologramException {
+ if (!observer.isOnline()) {
+ return;
+ }
+ try {
+ NMSHologramUtil.get().destroyEntity(entityId, observer);
+ } catch (ReflectiveOperationException cause) {
+ throw new HologramException("cannot destroy hologram entity", cause);
+ }
+ }
+
+}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSHologramUtil.java b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSHologramUtil.java
index c95ab8c7..fc4ab075 100644
--- a/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSHologramUtil.java
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/compatibility/nms/NMSHologramUtil.java
@@ -8,12 +8,11 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import java.util.List;
import java.util.Optional;
/**
* This class is used to perform reflection things
- * on server net classes to spawn holograms for all versions.
+ * on server net classes to spawn holograms for versions prior to 1.19.
*
* @author Utarwyn
* @since 2.2.0
@@ -94,21 +93,12 @@ private NMSHologramUtil() throws ReflectiveOperationException {
Class> entityPlayerClass = getNMSClass("EntityPlayer", "server.level");
Class> destroyPacketClass = getNMSClass("PacketPlayOutEntityDestroy", "network.protocol.game");
- // 1.19+ :: PacketPlayOutSpawnEntityLiving has been renamed PacketPlayOutSpawnEntity
- String spawnPacketClassName = ServerVersion.isNewerThan(ServerVersion.V1_18)
- ? "PacketPlayOutSpawnEntity" : "PacketPlayOutSpawnEntityLiving";
- Class> spawnPacketClass = getNMSClass(spawnPacketClassName, "network.protocol.game");
+ Class> spawnPacketClass = getNMSClass("PacketPlayOutSpawnEntityLiving", "network.protocol.game");
this.packetClass = getNMSClass("Packet", "network.protocol");
this.entityClass = getNMSClass("Entity", "world.entity");
this.craftWorldClass = getCraftbukkitClass("CraftWorld");
-
- // 1.19.3+ :: spawn packet constructor use Entity instead of LivingEntity
- if (ServerVersion.isNewerThan(ServerVersion.V1_19)) {
- this.spawnPacketConstructor = spawnPacketClass.getConstructor(this.entityClass);
- } else {
- this.spawnPacketConstructor = spawnPacketClass.getConstructor(getNMSClass("EntityLiving", "world.entity"));
- }
+ this.spawnPacketConstructor = spawnPacketClass.getConstructor(getNMSClass("EntityLiving", "world.entity"));
// 1.17+ :: try to use only one int in packet constructor parameters
try {
@@ -120,9 +110,7 @@ private NMSHologramUtil() throws ReflectiveOperationException {
}
// 1.17+ :: New way of retrieving player connection instance
- if (ServerVersion.isNewerThan(ServerVersion.V1_19_R3)) {
- this.playerConnectionField = entityPlayerClass.getField("c");
- } else if (ServerVersion.isNewerThan(ServerVersion.V1_16)) {
+ if (ServerVersion.isNewerThan(ServerVersion.V1_16)) {
this.playerConnectionField = entityPlayerClass.getField("b");
} else {
this.playerConnectionField = entityPlayerClass.getField("playerConnection");
@@ -151,13 +139,7 @@ private NMSHologramUtil() throws ReflectiveOperationException {
if (ServerVersion.isNewerThan(ServerVersion.V1_14)) {
Class> packetMetadataClass = getNMSClass("PacketPlayOutEntityMetadata", "network.protocol.game");
Class> dataWatcherClass = getNMSClass("DataWatcher", "network.syncher");
-
- // 1.19.3+ :: metadata packet use a list of datawatcher items
- if (ServerVersion.isNewerThan(ServerVersion.V1_19)) {
- this.metadataPacketConstructor = packetMetadataClass.getConstructor(int.class, List.class);
- } else {
- this.metadataPacketConstructor = packetMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class);
- }
+ this.metadataPacketConstructor = packetMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class);
} else {
this.metadataPacketConstructor = null;
}
@@ -192,12 +174,7 @@ public int spawnHologram(Location location, String text, Player observer) throws
Object entity = this.createHologramEntity(location.getWorld(), location.getX(), location.getY(), location.getZ(), text);
// 1.19.3+ — 1.18+ :: New method name in Entity class
- Method getId;
- if (ServerVersion.isNewerThan(ServerVersion.V1_19)) {
- getId = this.entityClass.getMethod(ServerVersion.isNewerThan(ServerVersion.V1_19_R2) ? "af" : "ah");
- } else {
- getId = getNMSDynamicMethod(this.entityClass, "getId", "ae");
- }
+ Method getId = getNMSDynamicMethod(this.entityClass, "getId", "ae");
int entityId = (int) getId.invoke(entity);
// Send the spawn packet for 1.8+
@@ -278,9 +255,7 @@ private Object createHologramEntity(World w, double x, double y, double z, Strin
Method fromStringOrNullMethod = this.chatMessageClass.getMethod("fromStringOrNull", String.class);
Object chatComponent = fromStringOrNullMethod.invoke(null, text);
- // 1.19+ :: method is now "b" (instead of "a")
- String methodNamePost17 = ServerVersion.isNewerThan(ServerVersion.V1_18) ? "b" : "a";
- getNMSDynamicMethod(entityObject.getClass(), "setCustomName", methodNamePost17, this.chatBaseComponentClass)
+ getNMSDynamicMethod(entityObject.getClass(), "setCustomName", "a", this.chatBaseComponentClass)
.invoke(entityObject, chatComponent);
} else {
Method setCustomName = entityObject.getClass().getMethod("setCustomName", String.class);
@@ -320,25 +295,9 @@ private Object createHologramEntity(World w, double x, double y, double z, Strin
* @throws ReflectiveOperationException if the packet cannot be instanciated
*/
private Object createEntityMetadataPacket(int entityId, Object entity) throws ReflectiveOperationException {
- Method getDataWatcher;
- if (ServerVersion.isNewerThan(ServerVersion.V1_19)) {
- getDataWatcher = this.entityClass.getMethod(ServerVersion.isNewerThan(ServerVersion.V1_19_R2) ? "aj" : "al");
- } else {
- getDataWatcher = getNMSDynamicMethod(this.entityClass, "getDataWatcher", "ai");
- }
+ Method getDataWatcher = getNMSDynamicMethod(this.entityClass, "getDataWatcher", "ai");
Object entityDataWatcher = getDataWatcher.invoke(entity);
- Object metadataPacket;
-
- // 1.19.3+ :: metadata packet use a list of datawatcher items
- if (ServerVersion.isNewerThan(ServerVersion.V1_19)) {
- Method getItemListMethod = entityDataWatcher.getClass().getMethod("b");
- metadataPacket = this.metadataPacketConstructor.newInstance(entityId, getItemListMethod.invoke(entityDataWatcher));
- } else {
- // 1.18+ :: New method name in Entity class
- metadataPacket = this.metadataPacketConstructor.newInstance(entityId, entityDataWatcher, false);
- }
-
- return metadataPacket;
+ return this.metadataPacketConstructor.newInstance(entityId, entityDataWatcher, false);
}
}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/Hologram.java b/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/Hologram.java
index ca4c588c..090e1377 100644
--- a/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/Hologram.java
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/Hologram.java
@@ -1,13 +1,10 @@
package fr.utarwyn.endercontainers.hologram;
-import fr.utarwyn.endercontainers.compatibility.nms.NMSHologramUtil;
-import org.bukkit.Location;
import org.bukkit.entity.Player;
/**
* This class is used to display a text above an enderchest block
* if the option blockNametag was set to true.
- * This class uses packets and supports versions from 1.8 to 1.15.
*
* @author Utarwyn
* @since 2.0.0
@@ -20,16 +17,6 @@ class Hologram {
*/
static final double LINE_HEIGHT = 0.23D;
- /**
- * The title of the hologram (its content)
- */
- private final String title;
-
- /**
- * The location where the hologram have to spawn
- */
- private final Location location;
-
/**
* The player who has to receive the hologram
*/
@@ -38,22 +25,25 @@ class Hologram {
/**
* Identifier of the spawned entity for the observer
*/
- private Integer entityId;
+ private final Integer entityId;
/**
* Construct an hologram and spawn it directly
*
* @param observer The observer who has to receive the hologram
- * @param title The title/content of the hologram
- * @param location The location of the hologram
- * @throws HologramException thrown if cannot spawn the hologram
+ * @param entityId The entity id of the hologram
*/
- Hologram(Player observer, String title, Location location) throws HologramException {
+ Hologram(Player observer, int entityId) {
this.observer = observer;
- this.title = title;
- this.location = location;
+ this.entityId = entityId;
+ }
- this.spawn();
+ public Player getObserver() {
+ return observer;
+ }
+
+ public Integer getEntityId() {
+ return entityId;
}
/**
@@ -65,32 +55,4 @@ boolean isObserverOnline() {
return this.observer != null && this.observer.isOnline();
}
- /**
- * Destroy the hologram for the observer with the stored entity id.
- *
- * @throws HologramException thrown if cannot destroy the hologram
- */
- void destroy() throws HologramException {
- if (this.entityId != null && this.entityId >= 0) {
- try {
- NMSHologramUtil.get().destroyEntity(this.entityId, this.observer);
- } catch (ReflectiveOperationException cause) {
- throw new HologramException("cannot destroy hologram entity", cause);
- }
- }
- }
-
- /**
- * Spawn the hologram.
- *
- * @throws HologramException thrown if cannot spawn the hologram
- */
- private void spawn() throws HologramException {
- try {
- this.entityId = NMSHologramUtil.get().spawnHologram(this.location, this.title, this.observer);
- } catch (ReflectiveOperationException cause) {
- throw new HologramException("cannot spawn hologram entity", cause);
- }
- }
-
}
diff --git a/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/HologramManager.java b/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/HologramManager.java
index 11f3c52d..4fb52463 100644
--- a/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/HologramManager.java
+++ b/plugin/src/main/java/fr/utarwyn/endercontainers/hologram/HologramManager.java
@@ -2,6 +2,8 @@
import fr.utarwyn.endercontainers.AbstractManager;
import fr.utarwyn.endercontainers.Managers;
+import fr.utarwyn.endercontainers.compatibility.ArmorStandAdapter;
+import fr.utarwyn.endercontainers.compatibility.CompatibilityHelper;
import fr.utarwyn.endercontainers.configuration.Files;
import fr.utarwyn.endercontainers.configuration.LocaleKey;
import fr.utarwyn.endercontainers.dependency.DependenciesManager;
@@ -16,9 +18,11 @@
import org.bukkit.scheduler.BukkitTask;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.function.Predicate;
import java.util.logging.Level;
/**
@@ -38,6 +42,10 @@ public class HologramManager extends AbstractManager implements Runnable {
* The BukkitTask object which manage the spawning/dispawning of holograms
*/
BukkitTask task;
+ /**
+ * The armor stand adapter
+ */
+ ArmorStandAdapter armorStandAdapter;
/**
* The enderchest manager
*/
@@ -69,6 +77,7 @@ private static String generateNametagTitle(int chestCount) {
public synchronized void load() {
this.chestManager = Managers.get(EnderChestManager.class);
this.dependenciesManager = Managers.get(DependenciesManager.class);
+ this.armorStandAdapter = CompatibilityHelper.createArmorStandAdapter();
this.holograms = new ConcurrentHashMap<>();
// Start the task only if the block nametag is enabled
@@ -103,8 +112,15 @@ public void run() {
.filter(player -> !disabledWorlds.contains(player.getWorld().getName()))
.forEach(this::checkHologramStatus);
- // Unused holograms can be cleared
- this.holograms.entrySet().removeIf(entry -> !entry.getValue().isObserverOnline());
+ // Unused holograms can be destroyed
+ Predicate