diff --git a/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplates.java b/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplates.java index 7366e49..32a7ddb 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplates.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplates.java @@ -39,8 +39,11 @@ import net.momirealms.customnameplates.common.event.EventManager; import net.momirealms.customnameplates.common.locale.TranslationManager; import net.momirealms.customnameplates.common.plugin.NameplatesPlugin; import net.momirealms.customnameplates.common.plugin.scheduler.SchedulerTask; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -127,12 +130,12 @@ public abstract class CustomNameplates implements NameplatesPlugin { /** * A map that tracks online players by their unique UUID, allowing quick access to player data. */ - protected ConcurrentHashMap onlinePlayerMap = new ConcurrentHashMap<>(); + protected Map onlinePlayerMap = new ConcurrentHashMap<>(); /** * A fast lookup map that associates entity IDs to player data (CNPlayer) for quick access. */ - protected ConcurrentHashMap entityIDFastLookup = new ConcurrentHashMap<>(); + protected Map entityIDFastLookup = new ConcurrentHashMap<>(); /** * Manages advances or progressions for players, such as achievements or level ups. @@ -462,4 +465,16 @@ public abstract class CustomNameplates implements NameplatesPlugin { public static CustomNameplates getInstance() { return instance; } + + @ApiStatus.Experimental + public void addPlayerUnsafe(int entityId, CNPlayer player) { + if (this.entityIDFastLookup.containsKey(entityId)) return; + this.entityIDFastLookup.put(entityId, player); + } + + @Nullable + @ApiStatus.Experimental + public CNPlayer removePlayerUnsafe(int entityId) { + return this.entityIDFastLookup.remove(entityId); + } } diff --git a/api/src/main/java/net/momirealms/customnameplates/api/DummyPlayer.java b/api/src/main/java/net/momirealms/customnameplates/api/DummyPlayer.java new file mode 100644 index 0000000..dfd54fd --- /dev/null +++ b/api/src/main/java/net/momirealms/customnameplates/api/DummyPlayer.java @@ -0,0 +1,109 @@ +package net.momirealms.customnameplates.api; + +import net.momirealms.customnameplates.api.util.Vector3; + +import java.util.Set; +import java.util.UUID; + +public class DummyPlayer extends AbstractCNPlayer { + private final CNPlayer target; + private final int megEntityId; + private final Vector3 position; + + public DummyPlayer(CustomNameplates plugin, CNPlayer delegate, int entityId, Vector3 location) { + super(plugin, delegate.channel()); + this.target = delegate; + this.megEntityId = entityId; + this.position = location; + } + + @Override + public int entityID() { + return this.megEntityId; + } + + @Override + public boolean hasPermission(String permission) { + return this.target.hasPermission(permission); + } + + @Override + public Vector3 position() { + return this.position; + } + + @Override + public String world() { + return this.target.world(); + } + + @Override + public boolean isOnline() { + return this.target.isOnline(); + } + + @Override + public boolean isSpectator() { + return false; + } + + @Override + public double scale() { + return this.target.scale(); + } + + @Override + public boolean isCrouching() { + return false; + } + + @Override + public long playerTime() { + return this.target.playerTime(); + } + + @Override + public boolean isFlying() { + return false; + } + + @Override + public int remainingAir() { + return this.target.remainingAir(); + } + + @Override + public Set passengers() { + return Set.of(); + } + + @Override + public boolean isInitialized() { + return false; + } + + @Override + public String name() { + return this.target.name(); + } + + @Override + public UUID uuid() { + return this.target.uuid(); + } + + @Override + public Object player() { + return this.target.player(); + } + + @Override + public String currentNameplate() { + return this.target.currentNameplate(); + } + + @Override + public String currentBubble() { + return this.target.currentBubble(); + } +} diff --git a/api/src/main/java/net/momirealms/customnameplates/api/feature/tag/UnlimitedTagManager.java b/api/src/main/java/net/momirealms/customnameplates/api/feature/tag/UnlimitedTagManager.java index 84c44f3..987c89f 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/feature/tag/UnlimitedTagManager.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/feature/tag/UnlimitedTagManager.java @@ -18,6 +18,7 @@ package net.momirealms.customnameplates.api.feature.tag; import net.momirealms.customnameplates.api.CNPlayer; +import net.momirealms.customnameplates.api.feature.JoinQuitListener; import net.momirealms.customnameplates.common.plugin.feature.Reloadable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -25,7 +26,7 @@ import org.jetbrains.annotations.Nullable; /** * An interface manages unlimited tags */ -public interface UnlimitedTagManager extends Reloadable { +public interface UnlimitedTagManager extends Reloadable, JoinQuitListener { /** * Called every tick to update the state of tags. diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java index a791755..cd1aae3 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java @@ -32,7 +32,6 @@ import java.util.*; import java.util.function.Predicate; public class TagRendererImpl implements TagRenderer { - private final CNPlayer owner; private final UnlimitedTagManager manager; private final Vector tagVector; diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/UnlimitedTagManagerImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/UnlimitedTagManagerImpl.java index cb2f6b7..b1e896d 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/UnlimitedTagManagerImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/UnlimitedTagManagerImpl.java @@ -52,11 +52,11 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitListener, PlayerListener { +public class UnlimitedTagManagerImpl implements UnlimitedTagManager, PlayerListener { private final CustomNameplates plugin; private final LinkedHashMap configs = new LinkedHashMap<>(); - private final ConcurrentHashMap tagRenderers = new ConcurrentHashMap<>(); + private final ConcurrentHashMap tagRenderers = new ConcurrentHashMap<>(); private NameTagConfig[] configArray = new NameTagConfig[0]; private int previewDuration; private boolean alwaysShow; @@ -142,7 +142,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis public void onPlayerJoin(CNPlayer player) { plugin.debug(() -> player.name() + " joined the server"); TagRendererImpl sender = new TagRendererImpl(this, player); - TagRendererImpl previous = tagRenderers.put(player.uuid(), sender); + TagRendererImpl previous = tagRenderers.put(player.entityID(), sender); if (previous != null) { previous.destroy(); } @@ -155,7 +155,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis @Override public void onPlayerQuit(CNPlayer player) { - TagRendererImpl sender = tagRenderers.remove(player.uuid()); + TagRendererImpl sender = tagRenderers.remove(player.entityID()); if (sender != null) { sender.destroy(); } @@ -208,7 +208,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis @Override public void onAddPlayer(CNPlayer owner, CNPlayer added) { - TagRendererImpl controller = tagRenderers.get(owner.uuid()); + TagRendererImpl controller = tagRenderers.get(owner.entityID()); if (controller != null) { controller.handlePlayerAdd(added); } @@ -216,12 +216,12 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis @Override public TagRenderer getTagRender(CNPlayer owner) { - return tagRenderers.get(owner.uuid()); + return tagRenderers.get(owner.entityID()); } @Override public void onRemovePlayer(CNPlayer owner, CNPlayer removed) { - TagRendererImpl controller = tagRenderers.get(owner.uuid()); + TagRendererImpl controller = tagRenderers.get(owner.entityID()); if (controller != null) { controller.handlePlayerRemove(removed); } @@ -229,7 +229,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis @Override public void onPlayerDataSet(CNPlayer owner, CNPlayer viewer, boolean isCrouching) { - TagRendererImpl controller = tagRenderers.get(owner.uuid()); + TagRendererImpl controller = tagRenderers.get(owner.entityID()); if (controller != null) { controller.handleEntityDataChange(viewer, isCrouching); } @@ -237,7 +237,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis @Override public void onPlayerAttributeSet(CNPlayer owner, CNPlayer viewer, double scale) { - TagRendererImpl controller = tagRenderers.get(owner.uuid()); + TagRendererImpl controller = tagRenderers.get(owner.entityID()); if (controller != null) { controller.handleAttributeChange(viewer, scale); } @@ -245,7 +245,7 @@ public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitLis @Override public void onPlayerGameModeChange(CNPlayer owner, CNPlayer viewer, boolean isSpectator) { - TagRendererImpl controller = tagRenderers.get(owner.uuid()); + TagRendererImpl controller = tagRenderers.get(owner.entityID()); if (controller != null) { controller.handleGameModeChange(viewer, isSpectator); } diff --git a/backend/src/main/resources/commands.yml b/backend/src/main/resources/commands.yml index eb26833..cc7ebca 100644 --- a/backend/src/main/resources/commands.yml +++ b/backend/src/main/resources/commands.yml @@ -148,7 +148,7 @@ bubbles_list: # A command to test some stuffs # Usage: [COMMAND] debug_test: - enable: false + enable: true permission: nameplates.command.debug.test usage: - /nameplates debug test diff --git a/gradle.properties b/gradle.properties index 14b2b74..dddf769 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=3.0.27.1 +project_version=3.0.27.2 config_version=37 project_group=net.momirealms @@ -19,7 +19,7 @@ jar_relocator_version=1.7 h2_driver_version=2.3.232 sqlite_driver_version=3.49.1.0 adventure_bundle_version=4.21.0 -adventure_platform_version=4.3.4 +adventure_platform_version=4.4.0 cloud_core_version=2.0.0 cloud_services_version=2.0.0 cloud_brigadier_version=2.0.0-beta.10 diff --git a/platforms/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/DebugTestCommand.java b/platforms/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/DebugTestCommand.java index d8433e9..195dd5c 100644 --- a/platforms/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/DebugTestCommand.java +++ b/platforms/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/DebugTestCommand.java @@ -17,10 +17,17 @@ package net.momirealms.customnameplates.bukkit.command.feature; +import net.momirealms.customnameplates.api.CNPlayer; +import net.momirealms.customnameplates.api.CustomNameplates; +import net.momirealms.customnameplates.api.DummyPlayer; +import net.momirealms.customnameplates.api.util.Vector3; import net.momirealms.customnameplates.bukkit.BukkitCustomNameplates; import net.momirealms.customnameplates.bukkit.command.BukkitCommandFeature; import net.momirealms.customnameplates.common.command.CustomNameplatesCommandManager; +import org.bukkit.Location; import org.bukkit.command.CommandSender; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.incendo.cloud.Command; import org.incendo.cloud.CommandManager; @@ -36,6 +43,23 @@ public class DebugTestCommand extends BukkitCommandFeature { return builder .senderType(Player.class) .handler(context -> { + Player owner = context.sender(); + Location loc = context.sender().getLocation().add(5,0,5); + CustomNameplates plugin = CustomNameplates.getInstance(); + CNPlayer cnPlayer = plugin.getPlayer(owner.getUniqueId()); + Entity entity = owner.getWorld().spawn(loc, ArmorStand.class, e -> { + int fakeEntityId = e.getEntityId(); + CNPlayer fakePlayer = new DummyPlayer(plugin, cnPlayer, fakeEntityId, new Vector3(loc.getX(), loc.getY(), loc.getZ())); + plugin.addPlayerUnsafe(fakeEntityId, fakePlayer); + plugin.getUnlimitedTagManager().onPlayerJoin(fakePlayer); + }); + plugin.getScheduler().sync().runLater(() -> { + entity.remove(); + CNPlayer fake = plugin.removePlayerUnsafe(entity.getEntityId()); + if (fake != null) { + plugin.getUnlimitedTagManager().onPlayerQuit(fake); + } + }, 100, null); }); }