4 Commits

Author SHA1 Message Date
Oliver
49f2dfd79a fancyholograms v3: Refactor trait commands and add warning if using dev build 2025-10-15 16:44:25 +02:00
Oliver
bef84f0366 fancydialogs: Add dialog close timeout 2025-10-15 16:26:50 +02:00
Oliver
1b2ec76eb5 fancydialogs: Remove tutorial command 2025-10-15 16:26:24 +02:00
Oliver
a85384df0c fancydialogs: Update dependencies 2025-10-15 16:26:09 +02:00
14 changed files with 88 additions and 188 deletions

View File

@@ -1 +1 @@
0.0.26 0.0.27

View File

@@ -14,13 +14,6 @@ plugins {
runPaper.folia.registerTask() runPaper.folia.registerTask()
val supportedVersions =
listOf(
"1.21.6",
"1.21.7",
"1.21.8",
)
allprojects { allprojects {
group = "de.oliver" group = "de.oliver"
version = getFDVersion() version = getFDVersion()
@@ -97,7 +90,7 @@ tasks {
minecraftVersion("1.21.10") minecraftVersion("1.21.10")
downloadPlugins { downloadPlugins {
modrinth("fancynpcs", "2.6.0.283") modrinth("fancynpcs", "2.8.0")
// hangar("ViaVersion", "5.3.2") // hangar("ViaVersion", "5.3.2")
// hangar("ViaBackwards", "5.3.2") // hangar("ViaBackwards", "5.3.2")
// modrinth("multiverse-core", "4.3.11") // modrinth("multiverse-core", "4.3.11")
@@ -169,34 +162,3 @@ val gitCommitMessage: Provider<String> = providers.exec {
fun getFDVersion(): String { fun getFDVersion(): String {
return file("VERSION").readText() return file("VERSION").readText()
} }
hangarPublish {
publications.register("plugin") {
version = project.version as String
id = "FancyDialogs"
channel = "Alpha"
apiKey.set(System.getenv("HANGAR_PUBLISH_API_TOKEN"))
platforms {
paper {
jar = tasks.shadowJar.flatMap { it.archiveFile }
platformVersions = supportedVersions
}
}
changelog = gitCommitMessage.get()
}
}
modrinth {
token.set(System.getenv("MODRINTH_PUBLISH_API_TOKEN"))
projectId.set("FancyDialogs")
versionNumber.set(getFDVersion())
versionType.set("alpha")
uploadFile.set(file("build/libs/${project.name}-${getFDVersion()}.jar"))
gameVersions.addAll(supportedVersions)
loaders.add("paper")
loaders.add("folia")
changelog.set(gitCommitMessage.get())
}

View File

@@ -4,6 +4,7 @@ import com.fancyinnovations.fancydialogs.api.data.DialogData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -12,12 +13,12 @@ public abstract class Dialog {
protected String id; protected String id;
protected DialogData data; protected DialogData data;
protected Set<UUID> viewers; protected Map<UUID, Long> viewers; // uuid, time opened
public Dialog(String id, DialogData data) { public Dialog(String id, DialogData data) {
this.id = id; this.id = id;
this.data = data; this.data = data;
this.viewers = ConcurrentHashMap.newKeySet(); this.viewers = new ConcurrentHashMap<>();
} }
public Dialog() { public Dialog() {
@@ -49,7 +50,7 @@ public abstract class Dialog {
* @return a set of UUIDs of players who have this dialog opened * @return a set of UUIDs of players who have this dialog opened
*/ */
public Set<UUID> getViewers() { public Set<UUID> getViewers() {
return Set.copyOf(viewers); return Set.copyOf(viewers.keySet());
} }
/** /**
@@ -58,13 +59,7 @@ public abstract class Dialog {
* @param uuid of the player to check * @param uuid of the player to check
* @return true if the dialog is opened for the player, false otherwise * @return true if the dialog is opened for the player, false otherwise
*/ */
public boolean isOpenedFor(UUID uuid) { public abstract boolean isOpenedFor(UUID uuid);
if (uuid == null) {
return false;
}
return viewers.contains(uuid);
}
/*** /***
* Checks if the dialog is opened for a specific player. * Checks if the dialog is opened for a specific player.
@@ -85,7 +80,8 @@ public abstract class Dialog {
if (player == null) { if (player == null) {
return; return;
} }
viewers.add(player.getUniqueId());
viewers.put(player.getUniqueId(), System.currentTimeMillis());
} }
@ApiStatus.Internal @ApiStatus.Internal
@@ -93,6 +89,7 @@ public abstract class Dialog {
if (player == null) { if (player == null) {
return; return;
} }
viewers.remove(player.getUniqueId()); viewers.remove(player.getUniqueId());
} }
} }

View File

@@ -9,7 +9,6 @@ import com.fancyinnovations.fancydialogs.api.data.DialogData;
import com.fancyinnovations.fancydialogs.commands.DialogCMD; import com.fancyinnovations.fancydialogs.commands.DialogCMD;
import com.fancyinnovations.fancydialogs.commands.FancyDialogsCMD; import com.fancyinnovations.fancydialogs.commands.FancyDialogsCMD;
import com.fancyinnovations.fancydialogs.commands.QuickActionsCMD; import com.fancyinnovations.fancydialogs.commands.QuickActionsCMD;
import com.fancyinnovations.fancydialogs.commands.TutorialCMD;
import com.fancyinnovations.fancydialogs.commands.types.DialogCommandType; import com.fancyinnovations.fancydialogs.commands.types.DialogCommandType;
import com.fancyinnovations.fancydialogs.config.FDFeatureFlags; import com.fancyinnovations.fancydialogs.config.FDFeatureFlags;
import com.fancyinnovations.fancydialogs.config.FancyDialogsConfig; import com.fancyinnovations.fancydialogs.config.FancyDialogsConfig;
@@ -243,7 +242,6 @@ public class FancyDialogsPlugin extends JavaPlugin implements FancyDialogs {
lamp.register(FancyDialogsCMD.INSTANCE); lamp.register(FancyDialogsCMD.INSTANCE);
lamp.register(DialogCMD.INSTANCE); lamp.register(DialogCMD.INSTANCE);
lamp.register(TutorialCMD.INSTANCE);
if (!FDFeatureFlags.DISABLE_QUICK_ACTIONS_DIALOG.isEnabled()) { if (!FDFeatureFlags.DISABLE_QUICK_ACTIONS_DIALOG.isEnabled()) {
lamp.register(QuickActionsCMD.INSTANCE); lamp.register(QuickActionsCMD.INSTANCE);
} }

View File

@@ -1,29 +0,0 @@
package com.fancyinnovations.fancydialogs.commands;
import com.fancyinnovations.fancydialogs.FancyDialogsPlugin;
import de.oliver.fancylib.translations.Translator;
import revxrsal.commands.annotation.Command;
import revxrsal.commands.annotation.Description;
import revxrsal.commands.bukkit.actor.BukkitCommandActor;
import revxrsal.commands.bukkit.annotation.CommandPermission;
public final class TutorialCMD {
public static final TutorialCMD INSTANCE = new TutorialCMD();
private final FancyDialogsPlugin plugin = FancyDialogsPlugin.get();
private final Translator translator = FancyDialogsPlugin.get().getTranslator();
private TutorialCMD() {
}
@Command("tutorial open <tutorial>")
@Description("Opens a specific tutorial dialog")
@CommandPermission("fancydialogs.commands.tutorial")
public void onTutorialOpen(
final BukkitCommandActor actor,
final String tutorial
) {
actor.requirePlayer().sendMessage("Opening tutorial: " + tutorial);
}
}

View File

@@ -12,6 +12,7 @@ public class FancyDialogsConfig {
private String logLevel; private String logLevel;
private String welcomeDialogID; private String welcomeDialogID;
private String quickActionsDialogID; private String quickActionsDialogID;
private long closeTimeout;
public void load() { public void load() {
FancyDialogsPlugin.get().reloadConfig(); FancyDialogsPlugin.get().reloadConfig();
@@ -29,6 +30,9 @@ public class FancyDialogsConfig {
quickActionsDialogID = (String) ConfigHelper.getOrDefault(config, "quick_actions_dialog_id", "quick_actions"); quickActionsDialogID = (String) ConfigHelper.getOrDefault(config, "quick_actions_dialog_id", "quick_actions");
config.setInlineComments("quick_actions_dialog_id", List.of("The ID of the dialog which will be shown to the player when they click on the quick actions key ('G' by default).")); config.setInlineComments("quick_actions_dialog_id", List.of("The ID of the dialog which will be shown to the player when they click on the quick actions key ('G' by default)."));
closeTimeout = (long) ConfigHelper.getOrDefault(config, "close_timeout", 1000L * 60 * 2);
config.setInlineComments("close_timeout", List.of("The time in milliseconds after which a dialog will be considered closed if the player does not respond. 0 means no timeout."));
FancyDialogsPlugin.get().saveConfig(); FancyDialogsPlugin.get().saveConfig();
} }
@@ -47,4 +51,8 @@ public class FancyDialogsConfig {
public String getQuickActionsDialogID() { public String getQuickActionsDialogID() {
return quickActionsDialogID; return quickActionsDialogID;
} }
public long getCloseTimeout() {
return closeTimeout;
}
} }

View File

@@ -27,6 +27,7 @@ import org.lushplugins.chatcolorhandler.parsers.ParserTypes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
public class DialogImpl extends Dialog { public class DialogImpl extends Dialog {
@@ -177,7 +178,7 @@ public class DialogImpl extends Dialog {
.createShowDialogPacket(buildForPlayer(player)) .createShowDialogPacket(buildForPlayer(player))
.send(new FS_RealPlayer(player)); .send(new FS_RealPlayer(player));
viewers.add(player.getUniqueId()); addViewer(player);
FancyDialogsPlugin.get().getFancyLogger().debug("Opened dialog " + id + " for player " + player.getName()); FancyDialogsPlugin.get().getFancyLogger().debug("Opened dialog " + id + " for player " + player.getName());
} }
@@ -188,9 +189,29 @@ public class DialogImpl extends Dialog {
.createClearDialogPacket() .createClearDialogPacket()
.send(new FS_RealPlayer(player)); .send(new FS_RealPlayer(player));
viewers.remove(player.getUniqueId()); removeViewer(player);
FancyDialogsPlugin.get().getFancyLogger().debug("Closed dialog " + id + " for player " + player.getName()); FancyDialogsPlugin.get().getFancyLogger().debug("Closed dialog " + id + " for player " + player.getName());
} }
@Override
public boolean isOpenedFor(UUID uuid) {
if (uuid == null) {
return false;
}
if (!viewers.containsKey(uuid)) {
return false;
}
long openedAt = viewers.get(uuid);
long now = System.currentTimeMillis();
if (now - openedAt > FancyDialogsPlugin.get().getFancyDialogsConfig().getCloseTimeout()) {
viewers.remove(uuid);
return false;
}
return true;
}
} }

View File

@@ -1,5 +1,6 @@
**ATTENTION**: v3 is still in development and contains breaking changes and potential bugs. **ATTENTION**: v3 is still in development and contains breaking changes and potential bugs.
Do not use this version in production at all, or you may lose data!! Do not use this version in production at all, or you may lose data!
Once migrated to v3, you cannot go back to v2 without losing all your holograms and configurations!
Commit hash: %COMMIT_HASH% Commit hash: %COMMIT_HASH%

View File

@@ -1 +1 @@
3.0.0-SNAPSHOT.6 3.0.0-SNAPSHOT.7

View File

@@ -202,10 +202,6 @@ public final class HologramCMD extends Command {
return Collections.emptyList(); return Collections.emptyList();
} }
if (args[2].equalsIgnoreCase("traits")) {
return new TraitsCMD().tabcompletion(sender, hologram, args);
}
// /holo edit [hologram] [option] {tab:contextual} // /holo edit [hologram] [option] {tab:contextual}
if (args.length == 4) { if (args.length == 4) {
final var suggestions = switch (args[2].toLowerCase(Locale.ROOT)) { final var suggestions = switch (args[2].toLowerCase(Locale.ROOT)) {
@@ -354,9 +350,6 @@ public final class HologramCMD extends Command {
} }
return switch (action) { return switch (action) {
// hologram data
case "traits" -> new TraitsCMD().run(player, hologram, args);
// display data // display data
case "moveto" -> new MoveToCMD().run(player, hologram, args); case "moveto" -> new MoveToCMD().run(player, hologram, args);
case "rotate" -> new RotateCMD().run(player, hologram, args); case "rotate" -> new RotateCMD().run(player, hologram, args);

View File

@@ -1,94 +0,0 @@
package com.fancyinnovations.fancyholograms.commands.hologram;
import com.fancyinnovations.fancyholograms.api.FancyHolograms;
import com.fancyinnovations.fancyholograms.api.hologram.Hologram;
import com.fancyinnovations.fancyholograms.api.trait.HologramTraitRegistry;
import com.fancyinnovations.fancyholograms.commands.Subcommand;
import de.oliver.fancylib.MessageHelper;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class TraitsCMD implements Subcommand {
@Override
public List<String> tabcompletion(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) {
if (args.length == 4) {
return List.of("add", "remove");
} else if (args.length == 5) {
return FancyHolograms.get().getTraitRegistry().getTraits()
.stream()
.filter(ti -> !ti.isDefault())
.filter(ti -> {
if (args[3].equalsIgnoreCase("add")) {
return !hologram.getData().getTraitTrait().isTraitAttached(ti.clazz());
} else if (args[3].equalsIgnoreCase("remove")) {
return hologram.getData().getTraitTrait().isTraitAttached(ti.clazz());
}
return true;
})
.map(HologramTraitRegistry.TraitInfo::name)
.toList();
}
return List.of();
}
@Override
public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) {
if (!(player.hasPermission("fancyholograms.hologram.edit.traits"))) {
MessageHelper.error(player, "You don't have the required permission to change traits of a hologram.");
return false;
}
// /hologram edit <name> traits <add|remove> <trait name>
if (args.length < 5) {
MessageHelper.error(player, "Usage: /hologram edit <name> traits <add|remove> <trait name>");
return false;
}
String action = args[3];
String traitName = args[4];
if (traitName == null || traitName.isEmpty()) {
MessageHelper.error(player, "You must specify a trait name.");
return false;
}
HologramTraitRegistry.TraitInfo traitInfo = FancyHolograms.get().getTraitRegistry().getTrait(traitName);
if (traitInfo == null) {
MessageHelper.error(player, "Trait '" + traitName + "' does not exist.");
return false;
}
switch (action.toLowerCase()) {
case "add": {
if (hologram.getData().getTraitTrait().isTraitAttached(traitInfo.clazz())) {
MessageHelper.error(player, "Trait '" + traitName + "' is already attached to hologram '" + hologram.getData().getName() + "'.");
return false;
}
hologram.getData().getTraitTrait().addTrait(traitInfo.clazz());
MessageHelper.success(player, "Trait '" + traitName + "' has been added to hologram '" + hologram.getData().getName() + "'.");
return true;
}
case "remove": {
if (!hologram.getData().getTraitTrait().isTraitAttached(traitInfo.clazz())) {
MessageHelper.error(player, "Trait '" + traitName + "' is not attached to hologram '" + hologram.getData().getName() + "'.");
return false;
}
hologram.getData().getTraitTrait().removeTrait(traitInfo.clazz());
MessageHelper.success(player, "Trait '" + traitName + "' has been removed from hologram '" + hologram.getData().getName() + "'.");
return true;
}
default: {
MessageHelper.error(player, "Invalid action. Use 'add' or 'remove'.");
return false;
}
}
}
}

View File

@@ -1,7 +1,9 @@
package com.fancyinnovations.fancyholograms.commands.lampCommands.hologram; package com.fancyinnovations.fancyholograms.commands.lampCommands.hologram;
import com.fancyinnovations.fancyholograms.api.hologram.Hologram; import com.fancyinnovations.fancyholograms.api.hologram.Hologram;
import com.fancyinnovations.fancyholograms.api.trait.HologramTrait;
import com.fancyinnovations.fancyholograms.api.trait.HologramTraitRegistry; import com.fancyinnovations.fancyholograms.api.trait.HologramTraitRegistry;
import com.fancyinnovations.fancyholograms.api.trait.HologramTraitTrait;
import com.fancyinnovations.fancyholograms.commands.lampCommands.suggestions.AttachedTraitsSuggestion; import com.fancyinnovations.fancyholograms.commands.lampCommands.suggestions.AttachedTraitsSuggestion;
import com.fancyinnovations.fancyholograms.commands.lampCommands.suggestions.DetachedTraitsSuggestion; import com.fancyinnovations.fancyholograms.commands.lampCommands.suggestions.DetachedTraitsSuggestion;
import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin; import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin;
@@ -70,4 +72,30 @@ public final class TraitCMD {
.replace("name", trait.name()) .replace("name", trait.name())
.send(actor.sender()); .send(actor.sender());
} }
@Command("hologram-new edit <hologram> trait list")
@Description("Lists all attached traits of a hologram")
@CommandPermission("fancyholograms.commands.hologram.trait.list")
public void list(
final @NotNull BukkitCommandActor actor,
final @NotNull Hologram hologram
) {
HologramTraitTrait traitTrait = hologram.getData().getTraitTrait();
if (traitTrait.getTraits().isEmpty()) {
translator.translate("commands.hologram.edit.trait.list.no_traits")
.replace("hologram", hologram.getData().getName())
.send(actor.sender());
return;
}
translator.translate("commands.hologram.edit.trait.list.header")
.replace("hologram", hologram.getData().getName())
.send(actor.sender());
for (HologramTrait trait : traitTrait.getTraits()) {
translator.translate("commands.hologram.edit.trait.list.entry")
.replace("name", trait.getName())
.send(actor.sender());
}
}
} }

View File

@@ -212,6 +212,17 @@ public final class FancyHologramsPlugin extends JavaPlugin implements FancyHolog
if (!configuration.areVersionNotificationsMuted()) { if (!configuration.areVersionNotificationsMuted()) {
checkForNewerVersion(); checkForNewerVersion();
} }
if (versionConfig.isDevelopmentBuild()) {
fancyLogger.warn("""
--------------------------------------------------
You are using a development build of FancyHolograms.
Please be aware that there might be bugs in this version.
If you find any bugs, please report them on our discord server (https://discord.gg/ZUgYCEJUEx).
Read more about the risks of using a development build here: https://docs.fancyinnovations.com/development-guidelines/versioning/#build
--------------------------------------------------
""");
}
metrics.register(); metrics.register();
metrics.registerLegacy(); metrics.registerLegacy();

View File

@@ -21,3 +21,7 @@ messages:
detach: detach:
not_attached: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> does not have trait {warningColor}{name}<gray> attached." not_attached: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> does not have trait {warningColor}{name}<gray> attached."
success: "<dark_gray> <gray>Successfully detached trait {warningColor}{name}<gray> from hologram {warningColor}{hologram}<gray>." success: "<dark_gray> <gray>Successfully detached trait {warningColor}{name}<gray> from hologram {warningColor}{hologram}<gray>."
list:
no_traits: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> does not have any traits attached."
header: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> has the following traits attached:"
entry: "<dark_gray> <gray> - {warningColor}{name}<gray>"