diff --git a/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java b/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java index cf75e407..05ad87be 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java @@ -39,7 +39,8 @@ public abstract class AbstractCNPlayer implements CNPlayer { private boolean isLoaded = false; - private boolean isPreviewing = false; + private boolean tempPreviewing = false; + private boolean toggleablePreviewing = false; private String equippedNameplate; private String equippedBubble; @@ -179,13 +180,22 @@ public void setLoaded(boolean loaded) { isLoaded = loaded; } - public void setPreviewing(boolean previewing) { - isPreviewing = previewing; + public void setTempPreviewing(boolean previewing) { + this.tempPreviewing = previewing; } @Override - public boolean isPreviewing() { - return isPreviewing; + public boolean isTempPreviewing() { + return tempPreviewing; + } + + public void setToggleablePreviewing(boolean previewing) { + this.toggleablePreviewing = previewing; + } + + @Override + public boolean isToggleablePreviewing() { + return toggleablePreviewing; } @Override @@ -468,6 +478,7 @@ public void save() { .uuid(uuid()) .nameplate(equippedNameplate()) .bubble(equippedBubble()) + .previewTags(isToggleablePreviewing()) .build(), plugin.getScheduler().async()); } diff --git a/api/src/main/java/net/momirealms/customnameplates/api/CNPlayer.java b/api/src/main/java/net/momirealms/customnameplates/api/CNPlayer.java index a7f09a0a..03da86c5 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/CNPlayer.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/CNPlayer.java @@ -115,7 +115,14 @@ public interface CNPlayer { * * @return true if the player is previewing, false otherwise */ - boolean isPreviewing(); + boolean isTempPreviewing(); + + /** + * Checks if the player has turned their nameplate on + * + * @return true if the player has turned their nameplate on, false otherwise + */ + boolean isToggleablePreviewing(); /** * Checks if the player has the specified permission. diff --git a/api/src/main/java/net/momirealms/customnameplates/api/ConfigManager.java b/api/src/main/java/net/momirealms/customnameplates/api/ConfigManager.java index 4f89525d..48678c5e 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/ConfigManager.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/ConfigManager.java @@ -70,6 +70,7 @@ public static YamlDocument getMainConfig() { protected int defaultConditionRefreshInterval; protected int delaySend; protected boolean catchOtherActionBar; + protected int otherActionBarStayTime; protected String namespace; protected String font; @@ -213,6 +214,7 @@ private void loadSettings() { defaultPlaceholderRefreshInterval = config.getInt("other-settings.default-placeholder-refresh-interval", 1); defaultConditionRefreshInterval = config.getInt("other-settings.ddefault-condition-refresh-interval", 1); catchOtherActionBar = config.getBoolean("other-settings.catch-other-plugin-actionbar", true); + otherActionBarStayTime = config.getInt("other-settings.other-actionbar-stay-time", 3000); } @Override @@ -336,6 +338,10 @@ public static int defaultConditionRefreshInterval() { return instance.defaultConditionRefreshInterval; } + public static int otherActionBarStayTime() { + return instance.otherActionBarStayTime; + } + public static boolean enableShader() { return instance.enableShader; } 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 01f0b4d6..cb883c7f 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplates.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplates.java @@ -79,6 +79,7 @@ public abstract class CustomNameplates implements NameplatesPlugin { protected ImageManager imageManager; protected NameplateManager nameplateManager; protected ResourcePackManager resourcePackManager; + protected CustomNameplatesAPI api; protected CustomNameplates() { instance = this; @@ -262,6 +263,15 @@ public ResourcePackManager getResourcePackManager() { return resourcePackManager; } + /** + * Get the API class + * + * @return api + */ + public CustomNameplatesAPI getAPI() { + return api; + } + /** * Returns the platform object for accessing platform-specific functionality. * diff --git a/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplatesAPI.java b/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplatesAPI.java new file mode 100644 index 00000000..a38f585c --- /dev/null +++ b/api/src/main/java/net/momirealms/customnameplates/api/CustomNameplatesAPI.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) <2024> + * + * 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 . + */ + +package net.momirealms.customnameplates.api; + +import net.momirealms.customnameplates.api.feature.AdaptiveImage; +import net.momirealms.customnameplates.api.feature.OffsetFont; +import net.momirealms.customnameplates.api.feature.background.Background; +import net.momirealms.customnameplates.api.feature.bubble.Bubble; +import net.momirealms.customnameplates.api.feature.nameplate.Nameplate; +import net.momirealms.customnameplates.api.helper.AdventureHelper; +import net.momirealms.customnameplates.api.placeholder.internal.StaticPosition; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.UUID; + +public record CustomNameplatesAPI(CustomNameplates plugin) { + + private static CustomNameplatesAPI instance; + + public CustomNameplatesAPI(CustomNameplates plugin) { + this.plugin = plugin; + instance = this; + } + + /** + * Gets the CustomNameplates plugin instance. + * + * @return the CustomNameplates plugin + */ + @Override + public CustomNameplates plugin() { + return plugin; + } + + /** + * Retrieves a player by their UUID. + * + * @param uuid the player's UUID + * @return the CNPlayer object if found, otherwise null + */ + @Nullable + public CNPlayer getPlayer(UUID uuid) { + return plugin.getPlayer(uuid); + } + + /** + * Retrieves a Background by its ID. + * + * @param id the background ID + * @return an Optional containing the Background if found, or empty if not + */ + @NotNull + public Optional getBackground(@NotNull String id) { + return Optional.ofNullable(plugin.getBackgroundManager().backgroundById(id)); + } + + /** + * Retrieves a Nameplate by its ID. + * + * @param id the nameplate ID + * @return an Optional containing the Nameplate if found, or empty if not + */ + @NotNull + public Optional getNameplate(@NotNull String id) { + return Optional.ofNullable(plugin.getNameplateManager().nameplateById(id)); + } + + /** + * Retrieves a Bubble by its ID. + * + * @param id the bubble ID + * @return an Optional containing the Bubble if found, or empty if not + */ + @NotNull + public Optional getBubble(@NotNull String id) { + return Optional.ofNullable(plugin.getBubbleManager().bubbleById(id)); + } + + /** + * Creates a text string with an image, applying margins around the image. + * + * @param text the text to be displayed + * @param adaptiveImage the image to insert with the text + * @param leftMargin the margin to apply on the left of the image + * @param rightMargin the margin to apply on the right of the image + * @return the resulting string with the image and margins + */ + @NotNull + public String createTextWithImage(@NotNull String text, @NotNull AdaptiveImage adaptiveImage, float leftMargin, float rightMargin) { + if (AdventureHelper.legacySupport) { + text = AdventureHelper.legacyToMiniMessage(text); + } + float advance = plugin.getAdvanceManager().getLineAdvance(text); + return adaptiveImage.createImagePrefix(advance, leftMargin, rightMargin) + text + adaptiveImage.createImageSuffix(advance, leftMargin, rightMargin); + } + + /** + * Gets the width advance (text length in visual representation) for a given text. + * + * @param text the text to measure + * @return the advance width of the text + */ + public float getTextAdvance(@NotNull String text) { + return plugin.getAdvanceManager().getLineAdvance(text); + } + + /** + * Creates a statically positioned text, aligning it to the left, right, or middle + * of the specified width. + * + * @param text the text to be positioned + * @param width the total width for the text positioning + * @param position the desired static position (LEFT, RIGHT, MIDDLE) + * @return the resulting string with the appropriate positioning + */ + @NotNull + public String createStaticText(@NotNull String text, int width, @NotNull StaticPosition position) { + float parsedWidth = CustomNameplates.getInstance().getAdvanceManager().getLineAdvance(text); + switch (position) { + case LEFT -> { + return text + AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)); + } + case RIGHT -> { + return AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)) + text; + } + case MIDDLE -> { + int half = (int) ((width - parsedWidth) / 2); + String left = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(half)); + String right = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth - half)); + return left + text + right; + } + default -> { + return ""; + } + } + } + + /** + * Returns the singleton instance of CustomNameplatesAPI. + * Throws an exception if the API has not been initialized. + * + * @return the CustomNameplatesAPI instance + */ + public static CustomNameplatesAPI getInstance() { + if (instance == null) { + throw new RuntimeException("Nameplates API has not been initialized yet."); + } + return instance; + } +} diff --git a/api/src/main/java/net/momirealms/customnameplates/api/feature/RespawnListener.java b/api/src/main/java/net/momirealms/customnameplates/api/feature/RespawnListener.java new file mode 100644 index 00000000..9c31a8b4 --- /dev/null +++ b/api/src/main/java/net/momirealms/customnameplates/api/feature/RespawnListener.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) <2024> + * + * 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 . + */ + +package net.momirealms.customnameplates.api.feature; + +import net.momirealms.customnameplates.api.CNPlayer; + +/** + * Listener for handling player respawn + */ +public interface RespawnListener { + + /** + * Called when a player respawns + * + * @param player the player who respawns + */ + void onRespawn(CNPlayer player); +} diff --git a/api/src/main/java/net/momirealms/customnameplates/api/feature/WorldChangeListener.java b/api/src/main/java/net/momirealms/customnameplates/api/feature/WorldChangeListener.java new file mode 100644 index 00000000..86384102 --- /dev/null +++ b/api/src/main/java/net/momirealms/customnameplates/api/feature/WorldChangeListener.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) <2024> + * + * 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 . + */ + +package net.momirealms.customnameplates.api.feature; + +import net.momirealms.customnameplates.api.CNPlayer; + +/** + * Listener for handling player change worlds + */ +public interface WorldChangeListener { + + /** + * Called when a player changes the world + * + * @param player the player who changes the world + */ + void onChangeWorld(CNPlayer player); +} 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 71a98983..acac7932 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 @@ -57,7 +57,15 @@ public interface UnlimitedTagManager extends Reloadable { * @param player the player to update * @param preview true to enable preview mode, false to disable */ - void setPreviewing(CNPlayer player, boolean preview); + void setTempPreviewing(CNPlayer player, boolean preview); + + /** + * Sets whether a player can always see their tags + * + * @param player the player to update + * @param preview true to enable preview mode, false to disable + */ + void togglePreviewing(CNPlayer player, boolean preview); /** * Returns the duration (in ticks) for which a tag preview is shown. diff --git a/api/src/main/java/net/momirealms/customnameplates/api/placeholder/internal/StaticText.java b/api/src/main/java/net/momirealms/customnameplates/api/placeholder/internal/StaticText.java index fc1f2362..49e59017 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/placeholder/internal/StaticText.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/placeholder/internal/StaticText.java @@ -19,6 +19,7 @@ import net.momirealms.customnameplates.api.CNPlayer; import net.momirealms.customnameplates.api.CustomNameplates; +import net.momirealms.customnameplates.api.CustomNameplatesAPI; import net.momirealms.customnameplates.api.feature.OffsetFont; import net.momirealms.customnameplates.api.feature.PreParsedDynamicText; import net.momirealms.customnameplates.api.helper.AdventureHelper; @@ -62,23 +63,6 @@ public String create(CNPlayer p1, CNPlayer p2) { } public String create(String text) { - float parsedWidth = CustomNameplates.getInstance().getAdvanceManager().getLineAdvance(text); - switch (position) { - case LEFT -> { - return text + AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)); - } - case RIGHT -> { - return AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)) + text; - } - case MIDDLE -> { - int half = (int) ((width - parsedWidth) / 2); - String left = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(half)); - String right = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth - half)); - return left + text + right; - } - default -> { - return ""; - } - } + return CustomNameplatesAPI.getInstance().createStaticText(text, width, position); } } diff --git a/api/src/main/java/net/momirealms/customnameplates/api/storage/data/JsonData.java b/api/src/main/java/net/momirealms/customnameplates/api/storage/data/JsonData.java index 12a06d36..70378a20 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/storage/data/JsonData.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/storage/data/JsonData.java @@ -32,6 +32,9 @@ public class JsonData { @SerializedName("bubble") private String bubble; + @SerializedName("flags") + private int flags; + /** * Constructs a new {@link JsonData} instance. * @@ -41,6 +44,27 @@ public class JsonData { public JsonData(String nameplate, String bubble) { this.nameplate = nameplate; this.bubble = bubble; + this.flags = 0; + } + + public JsonData(String nameplate, String bubble, int flags) { + this.nameplate = nameplate; + this.bubble = bubble; + this.flags = flags; + } + + public JsonData(String nameplate, String bubble, boolean previewState) { + this.nameplate = nameplate; + this.bubble = bubble; + this.flags = encodeFlags(previewState); + } + + public static int encodeFlags(boolean previewState) { + return previewState ? 1 : 0; + } + + public static boolean decodePreviewState(int flags) { + return (flags & 1) == 1; } /** @@ -61,6 +85,15 @@ public String bubble() { return bubble; } + /** + * Returns the flags + * + * @return flags + */ + public int getFlags() { + return flags; + } + /** * Converts this JSON data back into a {@link PlayerData} instance. * @@ -72,6 +105,7 @@ public PlayerData toPlayerData(UUID uuid) { .uuid(uuid) .nameplate(nameplate) .bubble(bubble) + .previewTags(decodePreviewState(flags)) .build(); } } diff --git a/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerData.java b/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerData.java index 889a5eb3..a2c988e5 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerData.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerData.java @@ -41,6 +41,13 @@ public interface PlayerData { */ String bubble(); + /** + * Returns if the tag should always be shown to the owner + * + * @return if the tag should always be shown to the owner + */ + boolean previewTags(); + /** * Returns the UUID of the player. * @@ -100,6 +107,14 @@ interface Builder { */ Builder uuid(UUID uuid); + /** + * Sets whether to preview state for the {@link PlayerData}. + * + * @param previewTags the state + * @return the builder instance + */ + Builder previewTags(boolean previewTags); + /** * Builds and returns the {@link PlayerData} instance. * @@ -114,6 +129,6 @@ interface Builder { * @return a {@link JsonData} object containing the nameplate and bubble data */ default JsonData toJsonData() { - return new JsonData(nameplate(), bubble()); + return new JsonData(nameplate(), bubble(), previewTags()); } } diff --git a/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerDataImpl.java b/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerDataImpl.java index d249b9d8..aec89934 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerDataImpl.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/storage/data/PlayerDataImpl.java @@ -28,11 +28,13 @@ public class PlayerDataImpl implements PlayerData { protected UUID uuid; protected String nameplate; protected String bubble; + protected boolean previewTags; - public PlayerDataImpl(UUID uuid, String nameplate, String bubble) { + public PlayerDataImpl(UUID uuid, String nameplate, String bubble, boolean previewTags) { this.uuid = uuid; this.nameplate = nameplate; this.bubble = bubble; + this.previewTags = previewTags; } @Override @@ -45,6 +47,11 @@ public String bubble() { return bubble; } + @Override + public boolean previewTags() { + return previewTags; + } + @Override public UUID uuid() { return uuid; @@ -57,6 +64,7 @@ public static class BuilderImpl implements Builder { private String nameplate; private String bubble; + private boolean previewTags; private UUID uuid; @Override @@ -77,9 +85,15 @@ public BuilderImpl uuid(UUID uuid) { return this; } + @Override + public Builder previewTags(boolean previewTags) { + this.previewTags = previewTags; + return this; + } + @Override public PlayerData build() { - return new PlayerDataImpl(uuid, nameplate, bubble); + return new PlayerDataImpl(uuid, nameplate, bubble, previewTags); } } } diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/actionbar/ActionBarSender.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/actionbar/ActionBarSender.java index e3d74452..42126007 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/actionbar/ActionBarSender.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/actionbar/ActionBarSender.java @@ -18,6 +18,7 @@ package net.momirealms.customnameplates.backend.feature.actionbar; import net.momirealms.customnameplates.api.CNPlayer; +import net.momirealms.customnameplates.api.ConfigManager; import net.momirealms.customnameplates.api.CustomNameplates; import net.momirealms.customnameplates.api.feature.CarouselText; import net.momirealms.customnameplates.api.feature.DynamicText; @@ -146,6 +147,10 @@ public void onHeartBeatTimer() { } public void refresh() { + if (currentActionBar == null) { + latestContent = ""; + return; + } latestContent = this.currentActionBar.render(owner); textChangeFlag = false; } @@ -181,8 +186,11 @@ public Set allPlaceholders() { @Override public void notifyPlaceholderUpdates(CNPlayer player, boolean force) { - refresh(); - sendLatestActionBar(); + // The actionbar should be visible before updating + if (currentActionBar != null) { + refresh(); + sendLatestActionBar(); + } } public void updateLastUpdateTime() { @@ -204,6 +212,6 @@ public String externalActionBar() { public void externalActionBar(@NotNull String externalActionBar) { requireNonNull(externalActionBar); this.externalActionBar = externalActionBar; - this.externalExpireTime = System.currentTimeMillis() + 3000; + this.externalExpireTime = System.currentTimeMillis() + ConfigManager.otherActionBarStayTime(); } } diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/bossbar/BossBarSender.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/bossbar/BossBarSender.java index cf29f0f6..51b82f61 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/bossbar/BossBarSender.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/bossbar/BossBarSender.java @@ -143,12 +143,12 @@ public void hide() { } public void show() { - isShown = true; - if (latestContent == null) { - refresh(); + if (this.latestContent == null) { + this.refresh(); } - Object packet = CustomNameplates.getInstance().getPlatform().createBossBarPacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(latestContent), progress(), overlay(), color()); + Object packet = CustomNameplates.getInstance().getPlatform().createBossBarPacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(this.latestContent), progress(), overlay(), color()); CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet); + isShown = true; } public boolean isShown() { @@ -172,18 +172,22 @@ public Set allPlaceholders() { @Override public void notifyPlaceholderUpdates(CNPlayer p1, boolean force) { - refresh(); if (isShown()) { + refresh(); sendLatestBossBarName(); } } public void refresh() { - latestContent = this.currentBossBar.render(owner); + if (this.currentBossBar == null) { + this.latestContent = ""; + return; + } + this.latestContent = this.currentBossBar.render(owner); } public void sendLatestBossBarName() { - if (latestContent != null && isShown()) { + if (this.latestContent != null && isShown()) { Object packet = CustomNameplates.getInstance().getPlatform().updateBossBarNamePacket(uuid, AdventureHelper.miniMessageToMinecraftComponent(latestContent)); CustomNameplates.getInstance().getPacketSender().sendPacket(owner, packet); } diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java index e7427e11..83430bd1 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java @@ -69,19 +69,21 @@ public void generate() { // save unicodes this.saveLegacyUnicodes(); - if (!VersionHelper.isVersionNewerThan1_20_5()) { - this.generateShaders("ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, false); - this.generateShaders("ResourcePack" + File.separator + "overlay_1_20_5" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true); - } else { - this.generateShaders("ResourcePack" + File.separator + "overlay_1_20_5" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true); - try { - FileUtils.copyDirectory( - new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_20_5"), - new File(plugin.getDataFolder(), "ResourcePack") - ); - FileUtils.deleteDirectory(new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_20_5")); - } catch (IOException e) { - throw new RuntimeException(e); + if (ConfigManager.enableShader()) { + if (!VersionHelper.isVersionNewerThan1_20_5()) { + this.generateShaders("ResourcePack" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, false); + this.generateShaders("ResourcePack" + File.separator + "overlay_1_20_5" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true); + } else { + this.generateShaders("ResourcePack" + File.separator + "overlay_1_20_5" + File.separator + "assets" + File.separator + "minecraft" + File.separator + "shaders" + File.separator + "core" + File.separator, true); + try { + FileUtils.copyDirectory( + new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_20_5"), + new File(plugin.getDataFolder(), "ResourcePack") + ); + FileUtils.deleteDirectory(new File(plugin.getDataFolder(), "ResourcePack" + File.separator + "overlay_1_20_5")); + } catch (IOException e) { + throw new RuntimeException(e); + } } } @@ -433,7 +435,6 @@ private void saveLegacyUnicodes() { } private void generateShaders(String path, boolean v1_20_5) { - if (!ConfigManager.enableShader()) return; plugin.getConfigManager().saveResource(path + "rendertype_text.fsh"); plugin.getConfigManager().saveResource(path + "rendertype_text.json"); diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/NameTag.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/NameTag.java index c08e91f3..e664e706 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/NameTag.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/NameTag.java @@ -131,16 +131,19 @@ public boolean canShow(CNPlayer viewer) { } public void refresh() { + if (!isShown()) return; for (CNPlayer viewer : viewerArray) { refresh(viewer); } } public void refresh(CNPlayer viewer) { - String newName = currentText.render(viewer); - Object component = AdventureHelper.miniMessageToMinecraftComponent(newName); - Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(CustomNameplates.getInstance().getPlatform().createTextComponentModifier(component))); - CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet); + if (isShown(viewer)) { + String newName = currentText.render(viewer); + Object component = AdventureHelper.miniMessageToMinecraftComponent(newName); + Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(CustomNameplates.getInstance().getPlatform().createTextComponentModifier(component))); + CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet); + } } @Override 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 f48e2a28..e3dc8062 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 @@ -24,7 +24,9 @@ import net.momirealms.customnameplates.api.ConfigManager; import net.momirealms.customnameplates.api.CustomNameplates; import net.momirealms.customnameplates.api.feature.CarouselText; +import net.momirealms.customnameplates.api.feature.RespawnListener; import net.momirealms.customnameplates.api.feature.JoinQuitListener; +import net.momirealms.customnameplates.api.feature.WorldChangeListener; import net.momirealms.customnameplates.api.feature.tag.NameTagConfig; import net.momirealms.customnameplates.api.feature.tag.TagRenderer; import net.momirealms.customnameplates.api.feature.tag.UnlimitedTagManager; @@ -40,8 +42,9 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; -public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitListener { +public class UnlimitedTagManagerImpl implements UnlimitedTagManager, JoinQuitListener, WorldChangeListener, RespawnListener { private final CustomNameplates plugin; private final LinkedHashMap configs = new LinkedHashMap<>(); @@ -55,24 +58,61 @@ public UnlimitedTagManagerImpl(CustomNameplates plugin) { } @Override - public void setPreviewing(CNPlayer player, boolean preview) { - boolean isPreviewing = player.isPreviewing(); + public void setTempPreviewing(CNPlayer player, boolean preview) { + boolean isPreviewing = player.isTempPreviewing(); if (isPreviewing) { if (preview) return; - plugin.getUnlimitedTagManager().onRemovePlayer(player, player); + onRemovePlayer(player, player); player.removePlayerFromTracker(player); - ((AbstractCNPlayer) player).setPreviewing(false); + ((AbstractCNPlayer) player).setTempPreviewing(false); } else { if (!preview) return; Tracker tracker = player.addPlayerToTracker(player); tracker.setScale(player.scale()); tracker.setCrouching(player.isCrouching()); tracker.setSpectator(player.isSpectator()); - plugin.getUnlimitedTagManager().onAddPlayer(player, player); - ((AbstractCNPlayer) player).setPreviewing(true); + onAddPlayer(player, player); + ((AbstractCNPlayer) player).setTempPreviewing(true); } } + @Override + public void togglePreviewing(CNPlayer player, boolean preview) { + boolean isPreviewing = player.isToggleablePreviewing(); + if (isPreviewing) { + if (preview) return; + onRemovePlayer(player, player); + player.removePlayerFromTracker(player); + ((AbstractCNPlayer) player).setToggleablePreviewing(false); + } else { + if (!preview) return; + Tracker tracker = player.addPlayerToTracker(player); + tracker.setScale(player.scale()); + tracker.setCrouching(player.isCrouching()); + tracker.setSpectator(player.isSpectator()); + onAddPlayer(player, player); + ((AbstractCNPlayer) player).setToggleablePreviewing(true); + } + } + + @Override + public void onChangeWorld(CNPlayer player) { + if (player.isTempPreviewing() || player.isToggleablePreviewing()) { + onRemovePlayer(player, player); + onAddPlayer(player, player); + } + } + + @Override + public void onRespawn(CNPlayer player) { + plugin.getScheduler().asyncLater(() -> { + if (player.isOnline() && (player.isTempPreviewing() || player.isToggleablePreviewing())) { + onRemovePlayer(player, player); + onAddPlayer(player, player); + } + }, 50, TimeUnit.MILLISECONDS); + } + @Override public int previewDuration() { return previewDuration; @@ -86,7 +126,9 @@ public void onPlayerJoin(CNPlayer player) { if (previous != null) { previous.destroy(); } - setPreviewing(player, isAlwaysShow()); + if (isAlwaysShow()) { + setTempPreviewing(player, isAlwaysShow()); + } } @Override diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/storage/StorageManagerImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/storage/StorageManagerImpl.java index 85d95f97..d2ffd5a9 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/storage/StorageManagerImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/storage/StorageManagerImpl.java @@ -95,6 +95,7 @@ public void onPlayerJoin(CNPlayer player) { private void handleDataLoad(CNPlayer player, PlayerData data) { player.equippedBubble(data.bubble()); player.equippedNameplate(data.nameplate()); + plugin.getUnlimitedTagManager().togglePreviewing(player, data.previewTags()); } @Override diff --git a/backend/src/main/resources/config.yml b/backend/src/main/resources/config.yml index 846065ae..8223101b 100644 --- a/backend/src/main/resources/config.yml +++ b/backend/src/main/resources/config.yml @@ -58,8 +58,9 @@ resource-pack: # Additional Settings: Extra options to control behavior and performance. other-settings: legacy-color-code-support: true # Enable support for legacy color codes using & - send-delay: 0 # Set actionbar/bossbar send delay + send-delay: 20 # Set actionbar/bossbar send delay (ticks) catch-other-plugin-actionbar: true # Capture actionbars from other plugins + other-actionbar-stay-time: 3000 # How long does other actionsbars stay (ms) unsafe-chat-event: false # Listen for canceled(unsafe) chat events from unknown plugins default-condition-refresh-interval: 1 # Set default condition refresh interval default-placeholder-refresh-interval: 1 # Set default placeholder refresh interval diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCustomNameplates.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCustomNameplates.java index b4125bda..bb172a2d 100644 --- a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCustomNameplates.java +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCustomNameplates.java @@ -20,7 +20,9 @@ import net.momirealms.customnameplates.api.*; import net.momirealms.customnameplates.api.event.NameplatesReloadEvent; import net.momirealms.customnameplates.api.feature.ChatListener; +import net.momirealms.customnameplates.api.feature.RespawnListener; import net.momirealms.customnameplates.api.feature.JoinQuitListener; +import net.momirealms.customnameplates.api.feature.WorldChangeListener; import net.momirealms.customnameplates.api.helper.VersionHelper; import net.momirealms.customnameplates.backend.feature.actionbar.ActionBarManagerImpl; import net.momirealms.customnameplates.backend.feature.advance.AdvanceManagerImpl; @@ -54,8 +56,11 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.plugin.java.JavaPlugin; import java.io.InputStream; @@ -78,6 +83,8 @@ public class BukkitCustomNameplates extends CustomNameplates implements Listener private final JavaPlugin bootstrap; private final List joinQuitListeners = new ArrayList<>(); + private final List worldChangeListeners = new ArrayList<>(); + private final List respawnListeners = new ArrayList<>(); private boolean loaded = false; @@ -154,11 +161,14 @@ public void enable() { this.chatManager = new BukkitChatManager(this); this.resourcePackManager = new ResourcePackManagerImpl(this); this.eventManager = EventManager.create(this); - - this.registerJoinQuitListener((JoinQuitListener) storageManager); - this.registerJoinQuitListener((JoinQuitListener) actionBarManager); - this.registerJoinQuitListener((JoinQuitListener) bossBarManager); - this.registerJoinQuitListener((JoinQuitListener) unlimitedTagManager); + this.api = new CustomNameplatesAPI(this); + + this.joinQuitListeners.add((JoinQuitListener) storageManager); + this.joinQuitListeners.add((JoinQuitListener) actionBarManager); + this.joinQuitListeners.add((JoinQuitListener) bossBarManager); + this.joinQuitListeners.add((JoinQuitListener) unlimitedTagManager); + this.worldChangeListeners.add((WorldChangeListener) unlimitedTagManager); + this.respawnListeners.add((RespawnListener) unlimitedTagManager); this.chatManager.registerListener((ChatListener) bubbleManager); Bukkit.getPluginManager().registerEvents(this, getBootstrap()); @@ -349,6 +359,26 @@ public void onQuit(PlayerQuitEvent event) { } } + @EventHandler(ignoreCancelled = true) + public void onChangeWorld(PlayerChangedWorldEvent event) { + CNPlayer cnPlayer = getPlayer(event.getPlayer().getUniqueId()); + if (cnPlayer != null) { + for (WorldChangeListener listener : worldChangeListeners) { + listener.onChangeWorld(cnPlayer); + } + } + } + + @EventHandler(ignoreCancelled = true) + public void onRespawn(PlayerRespawnEvent event) { + CNPlayer cnPlayer = getPlayer(event.getPlayer().getUniqueId()); + if (cnPlayer != null) { + for (RespawnListener listener : respawnListeners) { + listener.onRespawn(cnPlayer); + } + } + } + public BukkitSenderFactory getSenderFactory() { return senderFactory; } diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitPlatform.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitPlatform.java index 5bca6873..e043cdc3 100644 --- a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitPlatform.java +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitPlatform.java @@ -211,7 +211,7 @@ public BukkitPlatform(CustomNameplates plugin) { int vehicle = (int) Reflections.field$ClientboundSetPassengersPacket$vehicle.get(packet); CNPlayer another = CustomNameplates.getInstance().getPlayer(vehicle); if (another != null) { - Set otherEntities = player.getTrackedPassengerIds(another); + Set otherEntities = another.getTrackedPassengerIds(player); for (int passenger : passengers) { otherEntities.add(passenger); } diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/BukkitCommandManager.java index 6045576d..dacf00df 100644 --- a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/BukkitCommandManager.java @@ -57,6 +57,7 @@ public BukkitCommandManager(BukkitCustomNameplates plugin) { new NameplatesForceUnEquipCommand(this, plugin), new NameplatesForcePreviewCommand(this, plugin), new NameplatesForceEquipCommand(this, plugin), + new NameplatesToggleCommand(this, plugin), new BubblesForceUnEquipCommand(this, plugin), new BubblesListCommand(this, plugin), new BubblesUnEquipCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesForcePreviewCommand.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesForcePreviewCommand.java index 3c2d8290..d5b6f198 100644 --- a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesForcePreviewCommand.java +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesForcePreviewCommand.java @@ -79,8 +79,8 @@ public Command.Builder assembleCommand(CommandManager { if (!player.isOnline()) { @@ -88,7 +88,7 @@ public Command.Builder assembleCommand(CommandManager assembleCommand(CommandManager { if (!player.isOnline()) { return; } - plugin.getUnlimitedTagManager().setPreviewing(player, false); + plugin.getUnlimitedTagManager().setTempPreviewing(player, false); }, plugin.getUnlimitedTagManager().previewDuration(), TimeUnit.SECONDS); PreviewTasks.delayedTasks.put(player.uuid(), task); diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesToggleCommand.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesToggleCommand.java new file mode 100644 index 00000000..0ae1ea32 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/command/feature/NameplatesToggleCommand.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) <2024> + * + * 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 . + */ + +package net.momirealms.customnameplates.bukkit.command.feature; + +import net.momirealms.customnameplates.api.CNPlayer; +import net.momirealms.customnameplates.api.ConfigManager; +import net.momirealms.customnameplates.bukkit.BukkitCustomNameplates; +import net.momirealms.customnameplates.bukkit.command.BukkitCommandFeature; +import net.momirealms.customnameplates.common.command.CustomNameplatesCommandManager; +import net.momirealms.customnameplates.common.locale.MessageConstants; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; + +public class NameplatesToggleCommand extends BukkitCommandFeature { + + public NameplatesToggleCommand(CustomNameplatesCommandManager commandManager, BukkitCustomNameplates plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .senderType(Player.class) + .handler(context -> { + if (!ConfigManager.nameplateModule()) return; + CNPlayer player = plugin.getPlayer(context.sender().getUniqueId()); + if (player == null || !player.isLoaded()) return; + boolean isPreviewing = player.isToggleablePreviewing(); + plugin.getUnlimitedTagManager().togglePreviewing(player, !isPreviewing); + player.save(); + if (!isPreviewing) { + handleFeedback(context, MessageConstants.COMMAND_NAMEPLATES_TOGGLE_ON); + } else { + handleFeedback(context, MessageConstants.COMMAND_NAMEPLATES_TOGGLE_OFF); + } + }); + } + + @Override + public String getFeatureID() { + return "nameplates_toggle"; + } +} diff --git a/bukkit/src/main/resources/commands.yml b/bukkit/src/main/resources/commands.yml index f13636c4..eb26833b 100644 --- a/bukkit/src/main/resources/commands.yml +++ b/bukkit/src/main/resources/commands.yml @@ -87,6 +87,16 @@ nameplates_preview: usage: - /nameplates preview +# A command to toggle the nameplate previewing +# This command conflicts with `/nameplates preview` +# You should never enable both of them at the same time +# Usage: [COMMAND] +nameplates_toggle: + enable: false + permission: nameplates.command.toggle + usage: + - /nameplates toggle + # A command to view the available nameplates # Usage: [COMMAND] nameplates_list: diff --git a/common/src/main/java/net/momirealms/customnameplates/common/locale/MessageConstants.java b/common/src/main/java/net/momirealms/customnameplates/common/locale/MessageConstants.java index 1a5058d8..1b54bc58 100644 --- a/common/src/main/java/net/momirealms/customnameplates/common/locale/MessageConstants.java +++ b/common/src/main/java/net/momirealms/customnameplates/common/locale/MessageConstants.java @@ -38,6 +38,8 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_NAMEPLATES_LIST_FAILURE_NONE = Component.translatable().key("command.nameplates.list.failure.none"); TranslatableComponent.Builder COMMAND_NAMEPLATES_LIST_SUCCESS = Component.translatable().key("command.nameplates.list.success"); TranslatableComponent.Builder COMMAND_NAMEPLATES_LIST_DELIMITER = Component.translatable().key("command.nameplates.list.delimiter"); + TranslatableComponent.Builder COMMAND_NAMEPLATES_TOGGLE_ON = Component.translatable().key("command.nameplates.toggle.on"); + TranslatableComponent.Builder COMMAND_NAMEPLATES_TOGGLE_OFF = Component.translatable().key("command.nameplates.toggle.off"); TranslatableComponent.Builder COMMAND_NAMEPLATES_FORCE_EQUIP_SUCCESS = Component.translatable().key("command.nameplates.force_equip.success"); TranslatableComponent.Builder COMMAND_NAMEPLATES_FORCE_EQUIP_FAILURE_NOT_EXISTS = Component.translatable().key("command.nameplates.force_equip.failure.not_exists"); diff --git a/common/src/main/resources/translations/en.yml b/common/src/main/resources/translations/en.yml index b53c6691..322dcfc1 100644 --- a/common/src/main/resources/translations/en.yml +++ b/common/src/main/resources/translations/en.yml @@ -60,6 +60,8 @@ command.nameplates.force_equip.failure.not_exists: "Failed to equip namepla command.nameplates.force_equip.success: "Forced to equip " # use for display name command.nameplates.force_unequip.success: "Removed 's nameplate" command.nameplates.force_preview.success: "Forced to preview nameplates" +command.nameplates.toggle.on: "You're now showing your tags (Go to third person to view)" +command.nameplates.toggle.off: "Your tags have been hidden" command.bubbles.equip.failure.not_exists: " doesn't exist" command.bubbles.equip.failure.permission: "You don't have permission to use this bubble" command.bubbles.equip.failure.no_change: "Nothing changed as you have already equipped this bubble" diff --git a/common/src/main/resources/translations/zh_cn.yml b/common/src/main/resources/translations/zh_cn.yml index 3f4be760..f96ddc5b 100644 --- a/common/src/main/resources/translations/zh_cn.yml +++ b/common/src/main/resources/translations/zh_cn.yml @@ -60,6 +60,8 @@ command.nameplates.force_equip.failure.not_exists: "由于 不存 command.nameplates.force_equip.success: "强制 佩戴了铭牌 " command.nameplates.force_unequip.success: "移除了 的铭牌" command.nameplates.force_preview.success: "强制 预览他的铭牌" +command.nameplates.toggle.on: "你正在显示你的铭牌 (前往第三人称查看)" +command.nameplates.toggle.off: "你关闭了铭牌显示" command.bubbles.equip.failure.not_exists: "气泡 不存在" command.bubbles.equip.failure.permission: "你尚未解锁这个气泡" command.bubbles.equip.failure.no_change: "你已经应用这个气泡了" diff --git a/gradle.properties b/gradle.properties index 33595b07..98178ff7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=3.0.0-beta-2 -config_version=36 +project_version=3.0.0-beta-3 +config_version=37 project_group=net.momirealms # Dependency settings