diff --git a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/BlockHologramData.java b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/BlockHologramData.java index 5cce75200..81bf776d3 100644 --- a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/BlockHologramData.java +++ b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/BlockHologramData.java @@ -13,6 +13,7 @@ public class BlockHologramData extends DisplayHologramData { public static Material DEFAULT_BLOCK = Material.GRASS_BLOCK; private Material block = DEFAULT_BLOCK; + private String blockState = null; /** * @param name Name of hologram @@ -36,11 +37,25 @@ public BlockHologramData setBlock(Material block) { return this; } + public String getBlockState() { + return blockState; + } + + public BlockHologramData setBlockState(String blockState) { + if (!Objects.equals(this.blockState, blockState)) { + this.blockState = blockState; + setHasChanges(true); + } + + return this; + } + @Override @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { super.read(section, name); block = Material.getMaterial(section.getString("block", "GRASS_BLOCK").toUpperCase()); + blockState = section.getString("block_state", null); return true; } @@ -50,6 +65,7 @@ public boolean read(ConfigurationSection section, String name) { public boolean write(ConfigurationSection section, String name) { super.write(section, name); section.set("block", block.name()); + section.set("block_state", blockState); return true; } @@ -59,6 +75,7 @@ public BlockHologramData copy(String name) { BlockHologramData blockHologramData = new BlockHologramData(name, getLocation()); blockHologramData .setBlock(this.getBlock()) + .setBlockState(this.getBlockState()) .setScale(this.getScale()) .setShadowRadius(this.getShadowRadius()) .setShadowStrength(this.getShadowStrength()) diff --git a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/TextHologramData.java b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/TextHologramData.java index 06150ff48..12e6cd00c 100644 --- a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/TextHologramData.java +++ b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/data/TextHologramData.java @@ -21,6 +21,7 @@ public class TextHologramData extends DisplayHologramData { public static final boolean DEFAULT_TEXT_SHADOW_STATE = false; public static final boolean DEFAULT_SEE_THROUGH = false; public static final int DEFAULT_TEXT_UPDATE_INTERVAL = -1; + public static final byte DEFAULT_TEXT_OPACITY = (byte) 255; private List text = new ArrayList<>(DEFAULT_TEXT); private Color background = null; @@ -28,6 +29,7 @@ public class TextHologramData extends DisplayHologramData { private boolean textShadow = DEFAULT_TEXT_SHADOW_STATE; private boolean seeThrough = DEFAULT_SEE_THROUGH; private int textUpdateInterval = DEFAULT_TEXT_UPDATE_INTERVAL; + private byte textOpacity = DEFAULT_TEXT_OPACITY; /** * @param name Name of hologram @@ -150,6 +152,19 @@ public TextHologramData setTextUpdateInterval(int textUpdateInterval) { return this; } + public byte getTextOpacity() { + return textOpacity; + } + + public TextHologramData setTextOpacity(byte textOpacity) { + if (this.textOpacity != textOpacity) { + this.textOpacity = textOpacity; + setHasChanges(true); + } + + return this; + } + @Override @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { @@ -163,6 +178,7 @@ public boolean read(ConfigurationSection section, String name) { textShadow = section.getBoolean("text_shadow", DEFAULT_TEXT_SHADOW_STATE); seeThrough = section.getBoolean("see_through", DEFAULT_SEE_THROUGH); textUpdateInterval = section.getInt("update_text_interval", DEFAULT_TEXT_UPDATE_INTERVAL); + textOpacity = (byte) section.getInt("text_opacity", DEFAULT_TEXT_OPACITY); String textAlignmentStr = section.getString("text_alignment", DEFAULT_TEXT_ALIGNMENT.name().toLowerCase()); textAlignment = switch (textAlignmentStr.toLowerCase(Locale.ROOT)) { @@ -197,6 +213,7 @@ public boolean write(ConfigurationSection section, String name) { section.set("see_through", seeThrough); section.set("text_alignment", textAlignment.name().toLowerCase(Locale.ROOT)); section.set("update_text_interval", textUpdateInterval); + section.set("text_opacity", textOpacity); final String color; if (background == null) { @@ -223,6 +240,7 @@ public TextHologramData copy(String name) { .setTextShadow(this.hasTextShadow()) .setSeeThrough(this.isSeeThrough()) .setTextUpdateInterval(this.getTextUpdateInterval()) + .setTextOpacity(this.getTextOpacity()) .setScale(this.getScale()) .setShadowRadius(this.getShadowRadius()) .setShadowStrength(this.getShadowStrength()) diff --git a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/events/HologramUpdateEvent.java b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/events/HologramUpdateEvent.java index dab912b92..8fe493b7b 100644 --- a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/events/HologramUpdateEvent.java +++ b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/events/HologramUpdateEvent.java @@ -78,12 +78,15 @@ public enum HologramModification { BACKGROUND, TEXT_SHADOW, TEXT_ALIGNMENT, + TEXT_OPACITY, SEE_THROUGH, SHADOW_RADIUS, SHADOW_STRENGTH, UPDATE_TEXT_INTERVAL, UPDATE_VISIBILITY_DISTANCE, - GLOWING; + GLOWING, + BLOCK, + BLOCK_STATE; } } diff --git a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/hologram/HologramType.java b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/hologram/HologramType.java index 24c53a59b..1b3ff9592 100644 --- a/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/hologram/HologramType.java +++ b/plugins/fancyholograms/fh-api/src/main/java/com/fancyinnovations/fancyholograms/api/hologram/HologramType.java @@ -4,9 +4,9 @@ import java.util.List; public enum HologramType { - TEXT(Arrays.asList("background", "textshadow", "textalignment", "seethrough", "setline", "removeline", "addline", "insertbefore", "insertafter", "swapLines", "moveLineUp", "moveLineDown", "updatetextinterval")), + TEXT(Arrays.asList("background", "textshadow", "textalignment", "opacity", "seethrough", "setline", "removeline", "addline", "insertbefore", "insertafter", "swapLines", "moveLineUp", "moveLineDown", "updatetextinterval")), ITEM(List.of("item")), - BLOCK(List.of("block")); + BLOCK(Arrays.asList("block", "blockstate")); private final List commands; diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/HologramCMD.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/HologramCMD.java index 929a027fd..8f3d7150e 100644 --- a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/HologramCMD.java +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/HologramCMD.java @@ -52,11 +52,13 @@ public final class HologramCMD extends Command { <%primary_color%>- /hologram edit background - Changes the background of the hologram <%primary_color%>- /hologram edit textShadow - Enables/disables the text shadow <%primary_color%>- /hologram edit textAlignment - Sets the text alignment + <%primary_color%>- /hologram edit opacity <0-100> - Changes the opacity of the text hologram <%primary_color%>- /hologram edit seeThrough - Enables/disables whether the text can be seen through blocks <%primary_color%>- /hologram edit shadowRadius - Changes the shadow radius of the hologram <%primary_color%>- /hologram edit shadowStrength - Changes the shadow strength of the hologram <%primary_color%>- /hologram edit brightness <0-15> - Changes the brightness of the hologram <%primary_color%>- /hologram edit updateTextInterval - Sets the interval for updating the text + <%primary_color%>- /hologram edit blockState - Changes the block state (e.g., "facing north" for block holograms) <%primary_color%>- /hologram edit traits - Adds or removes a trait to the hologram """.replace("%primary_color%", MessageHelper.getPrimaryColor()); @@ -195,7 +197,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No final var usingNpcs = PluginUtils.isFancyNpcsEnabled(); - List suggestions = new ArrayList<>(Arrays.asList("traits", "position", "moveHere", "center", "moveTo", "rotate", "rotatepitch", "billboard", "scale", "translate", "visibilityDistance", "visibility", "shadowRadius", "shadowStrength", "brightness", usingNpcs ? "linkWithNpc" : "", usingNpcs ? "unlinkWithNpc" : "")); + List suggestions = new ArrayList<>(Arrays.asList("traits", "position", "moveHere", "center", "moveTo", "rotate", "rotatepitch", "billboard", "scale", "translate", "visibilityDistance", "visibility", "shadowRadius", "shadowStrength", "brightness", "glowing", usingNpcs ? "linkWithNpc" : "", usingNpcs ? "unlinkWithNpc" : "")); suggestions.addAll(type.getCommands()); return suggestions.stream().filter(input -> input.toLowerCase().startsWith(args[2].toLowerCase(Locale.ROOT))).toList(); @@ -259,6 +261,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No case "block" -> Arrays.stream(Material.values()).filter(Material::isBlock).map(Enum::name); case "seethrough" -> Stream.of("true", "false"); case "visibility" -> new VisibilityCMD().tabcompletion(sender, hologram, args).stream(); + case "glowing" -> new GlowingCMD().tabcompletion(sender, hologram, args).stream(); default -> null; }; @@ -368,6 +371,7 @@ private boolean edit(@NotNull final CommandSender player, @NotNull final Hologra case "shadowradius" -> new ShadowRadiusCMD().run(player, hologram, args); case "shadowstrength" -> new ShadowStrengthCMD().run(player, hologram, args); case "brightness" -> new BrightnessCMD().run(player, hologram, args); + case "glowing" -> new GlowingCMD().run(player, hologram, args); // text data case "background" -> new BackgroundCMD().run(player, hologram, args); @@ -378,6 +382,7 @@ private boolean edit(@NotNull final CommandSender player, @NotNull final Hologra case "insertafter" -> new InsertAfterCMD().run(player, hologram, args); case "textshadow" -> new TextShadowCMD().run(player, hologram, args); case "textalignment" -> new TextAlignmentCMD().run(player, hologram, args); + case "opacity" -> new OpacityCMD().run(player, hologram, args); case "seethrough" -> new SeeThroughCMD().run(player, hologram, args); // block data diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/hologram/GlowingCMD.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/hologram/GlowingCMD.java new file mode 100644 index 000000000..44170896a --- /dev/null +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/hologram/GlowingCMD.java @@ -0,0 +1,130 @@ +package com.fancyinnovations.fancyholograms.commands.hologram; + +import com.fancyinnovations.fancyholograms.api.data.DisplayHologramData; +import com.fancyinnovations.fancyholograms.api.events.HologramUpdateEvent; +import com.fancyinnovations.fancyholograms.api.hologram.Hologram; +import com.fancyinnovations.fancyholograms.commands.HologramCMD; +import com.fancyinnovations.fancyholograms.commands.Subcommand; +import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin; +import com.fancyinnovations.fancyholograms.utils.GlowingColor; +import de.oliver.fancylib.MessageHelper; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.stream.Collectors; + +public class GlowingCMD implements Subcommand { + + @Override + public List tabcompletion(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) { + if (args.length == 4) { + return Arrays.stream(GlowingColor.values()) + .map(color -> color.name().toLowerCase(Locale.ROOT)) + .collect(Collectors.toList()); + } + return null; + } + + @Override + public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) { + if (!(player.hasPermission("fancyholograms.hologram.edit.glowing"))) { + MessageHelper.error(player, "You don't have the required permission to change the glowing of a hologram"); + return false; + } + + if (!(hologram.getData() instanceof DisplayHologramData displayData)) { + MessageHelper.error(player, "This command can only be used on display holograms"); + return false; + } + + if (hologram.getData().getType() == com.fancyinnovations.fancyholograms.api.hologram.HologramType.TEXT) { + MessageHelper.error(player, "You can only make item and block holograms glow"); + return false; + } + + if (args.length == 3) { + final var copied = displayData.copy(displayData.getName()); + copied.setGlowing(!displayData.isGlowing()); + + if (!HologramCMD.callModificationEvent(hologram, player, copied, HologramUpdateEvent.HologramModification.GLOWING)) { + return false; + } + + displayData.setGlowing(copied.isGlowing()); + + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); + } + + MessageHelper.success(player, "Toggled glowing " + (displayData.isGlowing() ? "on" : "off")); + return true; + } + + final var colorArg = args[3].toLowerCase(Locale.ROOT); + + if (colorArg.equals("disabled")) { + final var copied = displayData.copy(displayData.getName()); + copied.setGlowing(false); + + if (!HologramCMD.callModificationEvent(hologram, player, copied, HologramUpdateEvent.HologramModification.GLOWING)) { + return false; + } + + displayData.setGlowing(false); + + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); + } + + MessageHelper.success(player, "Disabled glowing"); + return true; + } + + NamedTextColor color; + try { + GlowingColor glowingColor = GlowingColor.valueOf(colorArg.toUpperCase(Locale.ROOT)); + color = glowingColor.getColor(); + if (color == null) { + MessageHelper.error(player, "Could not parse glowing color"); + return false; + } + } catch (IllegalArgumentException e) { + MessageHelper.error(player, "Could not parse glowing color"); + return false; + } + + if (Objects.equals(color, displayData.getGlowingColor()) && displayData.isGlowing()) { + MessageHelper.warning(player, "This hologram already has this glowing color"); + return false; + } + + final var copied = displayData.copy(displayData.getName()); + copied.setGlowingColor(color); + copied.setGlowing(true); + + if (!HologramCMD.callModificationEvent(hologram, player, copied, HologramUpdateEvent.HologramModification.GLOWING_COLOR)) { + return false; + } + + if (Objects.equals(copied.getGlowingColor(), displayData.getGlowingColor()) && displayData.isGlowing()) { + MessageHelper.warning(player, "This hologram already has this glowing color"); + return false; + } + + displayData.setGlowingColor(copied.getGlowingColor()); + displayData.setGlowing(true); + + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); + } + + MessageHelper.success(player, "Changed glowing color"); + return true; + } +} \ No newline at end of file diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/hologram/OpacityCMD.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/hologram/OpacityCMD.java new file mode 100644 index 000000000..f09fdcd25 --- /dev/null +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/hologram/OpacityCMD.java @@ -0,0 +1,80 @@ +package com.fancyinnovations.fancyholograms.commands.hologram; + +import com.fancyinnovations.fancyholograms.api.data.TextHologramData; +import com.fancyinnovations.fancyholograms.api.events.HologramUpdateEvent; +import com.fancyinnovations.fancyholograms.api.hologram.Hologram; +import com.fancyinnovations.fancyholograms.commands.HologramCMD; +import com.fancyinnovations.fancyholograms.commands.Subcommand; +import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin; +import com.fancyinnovations.fancyholograms.util.NumberHelper; +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 OpacityCMD implements Subcommand { + + @Override + public List tabcompletion(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) { + return null; + } + + @Override + public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) { + + if (!(player.hasPermission("fancyholograms.hologram.edit.opacity"))) { + MessageHelper.error(player, "You don't have the required permission to edit a hologram"); + return false; + } + + if (!(hologram.getData() instanceof TextHologramData textData)) { + MessageHelper.error(player, "This command can only be used on text holograms"); + return false; + } + + final var parsedNumber = NumberHelper.parseInt(args[3]); + + if (parsedNumber.isEmpty()) { + MessageHelper.error(player, "Invalid opacity value."); + return false; + } + + final int opacityPercentage = parsedNumber.get(); + + if (opacityPercentage < 0 || opacityPercentage > 100) { + MessageHelper.error(player, "Invalid opacity value, must be between 0 and 100"); + return false; + } + + // Convert percentage (0-100) to byte value (0-255) + final byte opacity = (byte) Math.round(opacityPercentage * 255.0 / 100.0); + + if (opacity == textData.getTextOpacity()) { + MessageHelper.warning(player, "This hologram already has opacity set to " + opacityPercentage + "%"); + return false; + } + + final var copied = textData.copy(textData.getName()); + copied.setTextOpacity(opacity); + + if (!HologramCMD.callModificationEvent(hologram, player, copied, HologramUpdateEvent.HologramModification.TEXT_OPACITY)) { + return false; + } + + if (opacity == textData.getTextOpacity()) { + MessageHelper.warning(player, "This hologram already has opacity set to " + opacityPercentage + "%"); + return false; + } + + textData.setTextOpacity(copied.getTextOpacity()); + + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); + } + + MessageHelper.success(player, "Changed text opacity to " + opacityPercentage + "%"); + return true; + } +} diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/lampCommands/hologram/BlockStateCMD.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/lampCommands/hologram/BlockStateCMD.java new file mode 100644 index 000000000..4a05c7751 --- /dev/null +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/commands/lampCommands/hologram/BlockStateCMD.java @@ -0,0 +1,121 @@ +package com.fancyinnovations.fancyholograms.commands.lampCommands.hologram; + +import com.fancyinnovations.fancyholograms.api.data.BlockHologramData; +import com.fancyinnovations.fancyholograms.api.events.HologramUpdateEvent; +import com.fancyinnovations.fancyholograms.api.hologram.Hologram; +import com.fancyinnovations.fancyholograms.commands.HologramCMD; +import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancylib.MessageHelper; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.Default; +import revxrsal.commands.annotation.Description; +import revxrsal.commands.bukkit.actor.BukkitCommandActor; +import revxrsal.commands.bukkit.annotation.CommandPermission; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public final class BlockStateCMD { + + public static final BlockStateCMD INSTANCE = new BlockStateCMD(); + + private BlockStateCMD() { + } + + @Command("hologram-new edit blockstate ") + @Description("Sets or clears block state properties") + @CommandPermission("fancyholograms.hologram.edit.block_state") + public void blockState( + final @NotNull BukkitCommandActor actor, + final @NotNull Hologram hologram, + final @Default("") String args + ) { + if (!(hologram.getData() instanceof BlockHologramData blockData)) { + MessageHelper.error(actor.sender(), "This command can only be used on block holograms"); + return; + } + + // Split args by spaces + String[] argArray = args.trim().isEmpty() ? new String[0] : args.split("\\s+"); + + // If no args, clear the block state + if (argArray.length == 0) { + final var copied = blockData.copy(blockData.getName()); + copied.setBlockState(null); + + if (!HologramCMD.callModificationEvent(hologram, actor.sender(), copied, HologramUpdateEvent.HologramModification.BLOCK_STATE)) { + return; + } + + blockData.setBlockState(null); + + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); + } + + MessageHelper.success(actor.sender(), "Cleared block state (using default)"); + return; + } + + // Start with existing properties + Map existingProperties = new HashMap<>(); + + // Parse existing block state if present + if (blockData.getBlockState() != null && !blockData.getBlockState().isEmpty()) { + String[] props = blockData.getBlockState().split(","); + for (String prop : props) { + String[] parts = prop.split("=", 2); + if (parts.length == 2) { + existingProperties.put(parts[0].trim(), parts[1].trim()); + } + } + } + + // Parse property-value pairs from args + for (int i = 0; i < argArray.length; i += 2) { + if (i + 1 >= argArray.length) { + MessageHelper.error(actor.sender(), "Missing value for property: " + argArray[i]); + return; + } + existingProperties.put(argArray[i], argArray[i + 1]); + } + + // Build the block state string + String blockStateString = existingProperties.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .map(e -> e.getKey() + "=" + e.getValue()) + .collect(Collectors.joining(",")); + + // Validate the block state + try { + String fullBlockString = blockData.getBlock().getKey().toString() + "[" + blockStateString + "]"; + Bukkit.createBlockData(fullBlockString); + } catch (IllegalArgumentException e) { + MessageHelper.error(actor.sender(), "Invalid block state: " + e.getMessage()); + return; + } + + if (java.util.Objects.equals(blockStateString, blockData.getBlockState())) { + MessageHelper.warning(actor.sender(), "This block state is already set"); + return; + } + + final var copied = blockData.copy(blockData.getName()); + copied.setBlockState(blockStateString); + + if (!HologramCMD.callModificationEvent(hologram, actor.sender(), copied, HologramUpdateEvent.HologramModification.BLOCK_STATE)) { + return; + } + + blockData.setBlockState(blockStateString); + + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); + } + + MessageHelper.success(actor.sender(), "Set block state: " + blockStateString); + } +} diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/hologram/HologramImpl.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/hologram/HologramImpl.java index cae73f0e8..bc542a369 100644 --- a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/hologram/HologramImpl.java +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/hologram/HologramImpl.java @@ -156,6 +156,7 @@ private void syncWithData() { textDisplay.setStyleFlags((byte) 0); textDisplay.setShadow(textData.hasTextShadow()); textDisplay.setSeeThrough(textData.isSeeThrough()); + textDisplay.setTextOpacity(textData.getTextOpacity()); switch (textData.getTextAlignment()) { case LEFT -> textDisplay.setAlignLeft(true); @@ -170,9 +171,20 @@ private void syncWithData() { itemDisplay.setItem(itemData.getItemStack()); } else if (fsDisplay instanceof FS_BlockDisplay blockDisplay && data instanceof com.fancyinnovations.fancyholograms.api.data.BlockHologramData blockData) { // block - -// BlockType blockType = RegistryAccess.registryAccess().getRegistry(RegistryKey.BLOCK).get(blockData.getBlock().getKey()); - blockDisplay.setBlock(blockData.getBlock().createBlockData().createBlockState()); + try { + // If blockState is set, use it; otherwise use default + if (blockData.getBlockState() != null && !blockData.getBlockState().isEmpty()) { + // Create block data using full format: namespace:block[properties] + String fullBlockString = blockData.getBlock().getKey().toString() + "[" + blockData.getBlockState() + "]"; + blockDisplay.setBlock(org.bukkit.Bukkit.createBlockData(fullBlockString).createBlockState()); + } else { + blockDisplay.setBlock(blockData.getBlock().createBlockData().createBlockState()); + } + } catch (IllegalArgumentException e) { + // If block state is invalid, fall back to default + FancyHolograms.get().getFancyLogger().warn("Invalid block state for hologram " + blockData.getName() + ": " + e.getMessage()); + blockDisplay.setBlock(blockData.getBlock().createBlockData().createBlockState()); + } } if (data instanceof com.fancyinnovations.fancyholograms.api.data.DisplayHologramData displayData) { @@ -221,6 +233,30 @@ private void syncWithData() { } fsDisplay.setViewRange(displayData.getVisibilityDistance()); + + if (displayData.isGlowing()) { + int rgb = displayData.getGlowingColor().value() & 0xFFFFFF; + int argb = 0xFF000000 | rgb; + fsDisplay.setGlowColorOverride(argb); + + byte flags = 0x40; + try { + byte currentFlags = fsDisplay.getSharedFlags(); + flags = (byte) (currentFlags | 0x40); + } catch (NullPointerException ignored) { + } + fsDisplay.setSharedFlags(flags); + } else { + fsDisplay.setGlowColorOverride(-1); + + byte flags = 0; + try { + byte currentFlags = fsDisplay.getSharedFlags(); + flags = (byte) (currentFlags & ~0x40); + } catch (NullPointerException ignored) { + } + fsDisplay.setSharedFlags(flags); + } } } diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/main/FancyHologramsPlugin.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/main/FancyHologramsPlugin.java index 392d2cd63..fc411c7e8 100644 --- a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/main/FancyHologramsPlugin.java +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/main/FancyHologramsPlugin.java @@ -11,6 +11,7 @@ import com.fancyinnovations.fancyholograms.commands.FancyHologramsTestCMD; import com.fancyinnovations.fancyholograms.commands.HologramCMD; import com.fancyinnovations.fancyholograms.commands.lampCommands.fancyholograms.ConfigCMD; +import com.fancyinnovations.fancyholograms.commands.lampCommands.hologram.BlockStateCMD; import com.fancyinnovations.fancyholograms.commands.lampCommands.hologram.MoveDownCMD; import com.fancyinnovations.fancyholograms.commands.lampCommands.hologram.MoveUpCMD; import com.fancyinnovations.fancyholograms.commands.lampCommands.hologram.SwapLinesCMD; @@ -312,6 +313,7 @@ private void registerLampCommands() { // hologram commands lamp.register(TraitCMD.INSTANCE); + lamp.register(BlockStateCMD.INSTANCE); lamp.register(MoveUpCMD.INSTANCE); lamp.register(MoveDownCMD.INSTANCE); lamp.register(SwapLinesCMD.INSTANCE); diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/JsonAdapter.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/JsonAdapter.java index c21142461..d7c269b6e 100644 --- a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/JsonAdapter.java +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/JsonAdapter.java @@ -6,6 +6,7 @@ import com.fancyinnovations.fancyholograms.api.trait.HologramTraitRegistry; import com.fancyinnovations.fancyholograms.storage.json.model.*; import de.oliver.fancyanalytics.logger.properties.ThrowableProperty; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -63,19 +64,24 @@ public static JsonDisplayHologramData displayHologramDataToJson(com.fancyinnovat } public static JsonTextHologramData textHologramDataToJson(com.fancyinnovations.fancyholograms.api.data.TextHologramData data) { + // Convert byte (0-255) to percentage (0-100) + int opacityPercentage = Math.round(((int) data.getTextOpacity() & 0xFF) * 100.0f / 255.0f); + return new JsonTextHologramData( data.getText(), data.hasTextShadow(), data.isSeeThrough(), data.getTextAlignment(), data.getTextUpdateInterval(), + opacityPercentage, data.getBackground() == null ? "" : "#" + Integer.toHexString(data.getBackground().asARGB()) ); } public static JsonBlockHologramData blockHologramDataToJson(com.fancyinnovations.fancyholograms.api.data.BlockHologramData data) { return new JsonBlockHologramData( - data.getBlock().name() + data.getBlock().name(), + data.getBlockState() ); } @@ -168,12 +174,16 @@ public static com.fancyinnovations.fancyholograms.api.data.HologramData fromJson .setTextShadow(data.text_data().text_shadow()) .setSeeThrough(data.text_data().see_through()) .setTextUpdateInterval(data.text_data().text_update_interval()) + .setTextOpacity(data.text_data().text_opacity() != null + ? (byte) Math.round(data.text_data().text_opacity() * 255.0 / 100.0) + : (byte) 255) .setBillboard(data.display_data().billboard()) // display data .setScale(scale) .setTranslation(translation) .setBrightness(brightness) .setShadowRadius(data.display_data().shadow_radius()) .setShadowStrength(data.display_data().shadow_strength()) + .setGlowingColor(data.display_data().glowing_color() != null ? data.display_data().glowing_color() : com.fancyinnovations.fancyholograms.api.data.DisplayHologramData.DEFAULT_GLOWING_COLOR) .setWorldName(data.hologram_data().worldName())// hologram data .setVisibilityDistance(data.hologram_data().visibilityDistance()) .setVisibility(data.hologram_data().visibility()) @@ -196,6 +206,7 @@ public static com.fancyinnovations.fancyholograms.api.data.HologramData fromJson case BLOCK -> new com.fancyinnovations.fancyholograms.api.data.BlockHologramData(data.hologram_data().name(), loc) .setBlock(Material.getMaterial(data.block_data().block_material())) // block data + .setBlockState(data.block_data().block_state()) .setBillboard(data.display_data().billboard()) // display data .setScale(scale) .setTranslation(translation) diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonBlockHologramData.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonBlockHologramData.java index f793ae21a..a013684b7 100644 --- a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonBlockHologramData.java +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonBlockHologramData.java @@ -1,6 +1,7 @@ package com.fancyinnovations.fancyholograms.storage.json.model; public record JsonBlockHologramData( - String block_material + String block_material, + String block_state ) { } diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonTextHologramData.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonTextHologramData.java index 0fcb6a52f..7fec37282 100644 --- a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonTextHologramData.java +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/storage/json/model/JsonTextHologramData.java @@ -10,6 +10,7 @@ public record JsonTextHologramData( Boolean see_through, TextDisplay.TextAlignment text_alignment, Integer text_update_interval, + Integer text_opacity, String background_color ) { } diff --git a/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/utils/GlowingColor.java b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/utils/GlowingColor.java new file mode 100644 index 000000000..7f5d4d726 --- /dev/null +++ b/plugins/fancyholograms/src/main/java/com/fancyinnovations/fancyholograms/utils/GlowingColor.java @@ -0,0 +1,50 @@ +package com.fancyinnovations.fancyholograms.utils; + +import net.kyori.adventure.text.format.NamedTextColor; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public enum GlowingColor { + DISABLED(null, ""), + BLACK(NamedTextColor.BLACK, "color_black"), + DARK_BLUE(NamedTextColor.DARK_BLUE, "color_dark_blue"), + DARK_GREEN(NamedTextColor.DARK_GREEN, "color_dark_green"), + DARK_AQUA(NamedTextColor.DARK_AQUA, "color_dark_aqua"), + DARK_RED(NamedTextColor.DARK_RED, "color_dark_red"), + DARK_PURPLE(NamedTextColor.DARK_PURPLE, "color_dark_purple"), + GOLD(NamedTextColor.GOLD, "color_gold"), + GRAY(NamedTextColor.GRAY, "color_gray"), + DARK_GRAY(NamedTextColor.DARK_GRAY, "color_dark_gray"), + BLUE(NamedTextColor.BLUE, "color_blue"), + GREEN(NamedTextColor.GREEN, "color_green"), + AQUA(NamedTextColor.AQUA, "color_aqua"), + RED(NamedTextColor.RED, "color_red"), + LIGHT_PURPLE(NamedTextColor.LIGHT_PURPLE, "color_light_purple"), + YELLOW(NamedTextColor.YELLOW, "color_yellow"), + WHITE(NamedTextColor.WHITE, "color_white"); + + private final @Nullable NamedTextColor color; + private final @NotNull String translationKey; + + GlowingColor(final @Nullable NamedTextColor color, final @NotNull String translationKey) { + this.color = color; + this.translationKey = translationKey; + } + + public @Nullable NamedTextColor getColor() { + return color; + } + + public @NotNull String getTranslationKey() { + return translationKey; + } + + public static @NotNull GlowingColor fromAdventure(final @NotNull NamedTextColor color) { + for (final GlowingColor glowingColor : GlowingColor.values()) + if (glowingColor.color != null && glowingColor.color.value() == color.value()) + return glowingColor; + throw new IllegalArgumentException("UNSUPPORTED COLOR"); + } + +} \ No newline at end of file