Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sign updates #2581

Draft
wants to merge 6 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import net.md_5.bungee.api.ChatColor;
import org.bukkit.*;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
Expand Down Expand Up @@ -98,11 +100,26 @@ public String[] getSignLines(Sign sign) {
return output;
}

@Override
public String[] getSignLines(Sign sign, Side side) {
String[] output = new String[4];
int i = 0;
for (Component component : sign.getSide(side).lines()) {
output[i++] = PaperModule.stringifyComponent(component);
}
return output;
}

@Override
public void setSignLine(Sign sign, int line, String text) {
sign.line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK));
}

@Override
public void setSignLine(Sign sign, Side side, int line, String text) {
sign.getSide(side).line(line, PaperModule.parseFormattedText(text == null ? "" : text, ChatColor.BLACK));
}

@Override
public void sendResourcePack(Player player, String url, String hash, boolean forced, String prompt) {
if (prompt == null && !forced) {
Expand All @@ -122,6 +139,17 @@ public void sendSignUpdate(Player player, Location loc, String[] text) {
player.sendSignChange(loc, components);
}

@Override
public void sendSignUpdate(Player player, Location loc, String[] text, Side side) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason this has a per-platfrom impl? the only platform specific code is setting the lines onto a Sign, which there's already PaperAPITools#setSignLine for - should be able to have this directly in the mechanism and just use that to set the lines

Sign sign = (Sign)loc.getBlock().getState();
SignSide signSide = sign.getSide(side);
signSide.lines().clear();
for (String s : text) {
signSide.lines().add(PaperModule.parseFormattedText((s == null ? "" : s), ChatColor.BLACK));
}
Comment on lines +146 to +149
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JavaDocs don't seem to specify the list being a live view (I.e. not just a copy or anything), so probably safer to set these like the other methods do

player.sendBlockUpdate(loc, sign);
}

@Override
public String getCustomName(Nameable object) {
return PaperModule.stringifyComponent(object.customName());
Expand Down
221 changes: 197 additions & 24 deletions plugin/src/main/java/com/denizenscript/denizen/objects/LocationTag.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.denizenscript.denizen.objects;

import com.denizenscript.denizen.utilities.MultiVersionHelper1_20;
import com.denizenscript.denizen.events.BukkitScriptEvent;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.NMSVersion;
Expand All @@ -18,10 +19,11 @@
import com.denizenscript.denizen.utilities.flags.LocationFlagSearchHelper;
import com.denizenscript.denizen.utilities.world.PathFinder;
import com.denizenscript.denizen.utilities.world.WorldListChangeTracker;
import com.denizenscript.denizencore.objects.core.*;
import com.denizenscript.denizencore.utilities.EnumHelper;
import com.denizenscript.denizencore.flags.AbstractFlagTracker;
import com.denizenscript.denizencore.flags.FlaggableObject;
import com.denizenscript.denizencore.objects.*;
import com.denizenscript.denizencore.objects.core.*;
import com.denizenscript.denizencore.objects.notable.Notable;
import com.denizenscript.denizencore.objects.notable.Note;
import com.denizenscript.denizencore.objects.notable.NoteManager;
Expand All @@ -40,6 +42,7 @@
import org.bukkit.block.banner.PatternType;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.sign.Side;
import org.bukkit.block.structure.Mirror;
import org.bukkit.block.structure.StructureRotation;
import org.bukkit.block.structure.UsageMode;
Expand Down Expand Up @@ -1238,15 +1241,22 @@ public static void register() {
// @mechanism LocationTag.sign_contents
// @group world
// @description
// Pre 1.20
// Returns a list of lines on a sign.
// 1.20+
// Returns a map of each side and lines on that side.
// -->
tagProcessor.registerTag(ListTag.class, "sign_contents", (attribute, object) -> {
if (object.getBlockStateForTag(attribute) instanceof Sign) {
return new ListTag(Arrays.asList(PaperAPITools.instance.getSignLines(((Sign) object.getBlockStateForTag(attribute)))));
}
else {
BlockState state = object.getBlockStateForTag(attribute);
if (!(state instanceof Sign)) {
attribute.echoError("Location is not a valid Sign block.");
return null;
}
if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_19)) {
return new ListTag(Arrays.asList(PaperAPITools.instance.getSignLines(((Sign) state))));
}
String side = attribute.hasParam() ? attribute.getParam() : "front";
return new ListTag(Arrays.asList(PaperAPITools.instance.getSignLines(((Sign) state), Side.valueOf(side.toUpperCase()))));
});

// <--[tag]
Expand Down Expand Up @@ -4127,14 +4137,19 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk
// @group world
// @description
// Returns whether the location is a Sign block that is glowing.
// Optionally provide a side (defaults to "front")
// -->
tagProcessor.registerTag(ElementTag.class, "sign_glowing", (attribute, object) -> {
BlockState state = object.getBlockStateForTag(attribute);
if (!(state instanceof Sign)) {
attribute.echoError("Location is not a valid Sign block.");
return null;
}
return new ElementTag(((Sign) state).isGlowingText());
if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_19)) {
return new ElementTag(((Sign) state).isGlowingText());
}
String side = attribute.hasParam() ? attribute.getParam() : "front";
return new ElementTag(((Sign) state).getSide(Side.valueOf(side.toUpperCase())).isGlowingText());
});

// <--[tag]
Expand All @@ -4143,7 +4158,9 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk
// @mechanism LocationTag.sign_glow_color
// @group world
// @description
// Pre 1.20
// Returns the name of the glow-color of the sign at the location.
// Optionally provide a side (defaults to "front")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, probably a separate tag to get the back's glow color, that way it can properly have a matching mechanism as well

// See also <@link tag LocationTag.sign_glowing>
// -->
tagProcessor.registerTag(ElementTag.class, "sign_glow_color", (attribute, object) -> {
Expand All @@ -4152,9 +4169,34 @@ else if (material.hasModernData() && material.getModernData() instanceof org.buk
attribute.echoError("Location is not a valid Sign block.");
return null;
}
return new ElementTag(((Sign) state).getColor());
if (NMSHandler.getVersion().isAtMost(NMSVersion.v1_19)) {
return new ElementTag(((Sign) state).getColor());
}
String side = attribute.hasParam() ? attribute.getParam() : "front";
return new ElementTag(((Sign) state).getSide(Side.valueOf(side.toUpperCase())).getColor());
});

// <--[tag]
// @attribute <LocationTag.sign_waxed>
// @returns ElementTag(Boolean)
// @mechanism LocationTag.sign_waxed
// @group world
// @description
// Returns whether the location is a Sign block that is waxed.
// See also <@link tag LocationTag.sign_glowing>
// -->
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) {
tagProcessor.registerTag(ElementTag.class, "sign_waxed", (attribute, object) -> {
BlockState state = object.getBlockStateForTag(attribute);
if (!(state instanceof Sign)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use instanceof pattern matching, that way you can use object.getBlockStateForTag(attribute) directly in the instanceof check instead of storing it separately and casting later

attribute.echoError("Location is not a valid Sign block.");
return null;
}
return new ElementTag(((Sign) state).isWaxed());
});
}


// <--[tag]
// @attribute <LocationTag.map_color>
// @returns ColorTag
Expand Down Expand Up @@ -4672,22 +4714,64 @@ public void adjust(Mechanism mechanism) {
// @tags
// <LocationTag.sign_contents>
// -->
if (mechanism.matches("sign_contents") && getBlockState() instanceof Sign) {
Sign state = (Sign) getBlockState();
for (int i = 0; i < 4; i++) {
PaperAPITools.instance.setSignLine(state, i, "");
}
ListTag list = mechanism.valueAsType(ListTag.class);
CoreUtilities.fixNewLinesToListSeparation(list);
if (list.size() > 4) {
mechanism.echoError("Sign can only hold four lines!");
if (mechanism.matches("sign_contents")) {
BlockState state = getBlockState();
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_contents' mechanism can only be called on Sign blocks.");
} else {
Comment on lines +4717 to +4721
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to update this mechanism should move it to modern tagProcessor#registerMechanism.
Also should use early return for these error checks instead of nested if/else

for (int i = 0; i < 4; i++) {
PaperAPITools.instance.setSignLine(sign, i, "");
}
ListTag list = mechanism.valueAsType(ListTag.class);
CoreUtilities.fixNewLinesToListSeparation(list);
if (list.size() > 4) {
mechanism.echoError("Sign can only hold four lines!");
} else {
for (int i = 0; i < list.size(); i++) {
PaperAPITools.instance.setSignLine(sign, i, list.get(i));
}
}
state.update();
}
else {
for (int i = 0; i < list.size(); i++) {
PaperAPITools.instance.setSignLine(state, i, list.get(i));
}

// <--[mechanism]
// @object LocationTag
// @name sign_sides_contents
// @input MapTag
// @description
// Sets the contents of each side for a sign block.
// The input map keys are either 'Front' or 'Back'
// @tags
// <LocationTag.sign_contents>
// -->
if (mechanism.matches("sign_sides_contents") && mechanism.requireObject(MapTag.class)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New mechanisms should be added using the modern registerMechanism.
Also instead of a map with keys for both sides, might be easier to understand as a mech+tag pair for the front (which already exists) and a mech+tag pair for the back? I.e. something like sign_back_contents

BlockState state = getBlockState();
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_sides_contents' mechanism can only be called on Sign blocks.");
} else {
MapTag contentMap = mechanism.valueAsType(MapTag.class);
for (Map.Entry<StringHolder, ObjectTag> entry : contentMap.map.entrySet()) {
if (EnumHelper.get(Side.class).valuesMapLower.containsKey(entry.getKey().str)) {
Side side = Side.valueOf(entry.getKey().toString().toUpperCase());
for (int i = 0; i < 4; i++) {
PaperAPITools.instance.setSignLine(sign, side, i, "");
}
ListTag list = entry.getValue().asType(ListTag.class, mechanism.context);
CoreUtilities.fixNewLinesToListSeparation(list);
if (list.size() > 4) {
mechanism.echoError("Sign can only hold four lines!");
} else {
for (int i = 0; i < list.size(); i++) {
PaperAPITools.instance.setSignLine(sign, side, i, list.get(i));
}
}
} else {
mechanism.echoError("Unknown sign side " + entry.getKey());
}
}
state.update();
}
state.update();
}

// <--[mechanism]
Expand Down Expand Up @@ -5345,16 +5429,46 @@ else if (state instanceof Dropper) {
// -->
if (mechanism.matches("sign_glowing") && mechanism.requireBoolean()) {
BlockState state = getBlockState();
if (!(state instanceof Sign)) {
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_glowing' mechanism can only be called on Sign blocks.");
}
else {
Sign sign = (Sign) state;
sign.setGlowingText(mechanism.getValue().asBoolean());
sign.update();
}
}

// <--[mechanism]
// @object LocationTag
// @name sign_sides_glowing
// @input MapTag
// @description
// Changes whether each side for a sign block is glowing.
// The input map keys are either 'Front' or 'Back'
// @tags
// <LocationTag.sign_glow_color>
// <LocationTag.sign_glowing>
// -->
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) {
if (mechanism.matches("sign_sides_glowing") && mechanism.requireObject(MapTag.class)) {
BlockState state = getBlockState();
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_sides_glowing' mechanism can only be called on Sign blocks.");
} else {
MapTag glowMap = mechanism.valueAsType(MapTag.class);
for (Map.Entry<StringHolder, ObjectTag> entry : glowMap.map.entrySet()) {
if (EnumHelper.get(Side.class).valuesMapLower.containsKey(entry.getKey().str)) {
Side side = Side.valueOf(entry.getKey().toString().toUpperCase());
sign.getSide(side).setGlowingText(entry.getValue().asElement().asBoolean());
} else {
mechanism.echoError("Unknown sign side " + entry.getKey());
}
}
sign.update();
}
}
}

// <--[mechanism]
// @object LocationTag
// @name sign_glow_color
Expand All @@ -5370,16 +5484,75 @@ else if (state instanceof Dropper) {
// -->
if (mechanism.matches("sign_glow_color") && mechanism.requireEnum(DyeColor.class)) {
BlockState state = getBlockState();
if (!(state instanceof Sign)) {
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_glow_color' mechanism can only be called on Sign blocks.");
}
else {
Sign sign = (Sign) state;
sign.setColor(mechanism.getValue().asEnum(DyeColor.class));
sign.update();
}
}

// <--[mechanism]
// @object LocationTag
// @name sign_sides_glow_color
// @input MapTag
// @description
// Changes the glow color of each side of the sign.
// For the list of possible colors, see <@link url https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html>.
// If a sign is not glowing, this is equivalent to applying a chat color to the sign.
// The input map keys are either 'Front' or 'Back'
// Use <@link mechanism LocationTag.sign_glowing> to toggle whether the sign is glowing.
// @tags
// <LocationTag.sign_glow_color>
// <LocationTag.sign_glowing>
// -->
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) {
if (mechanism.matches("sign_sides_glow_color") && mechanism.requireObject(MapTag.class)) {
BlockState state = getBlockState();
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_sides_glow_color' mechanism can only be called on Sign blocks.");
} else {
MapTag glowMap = mechanism.valueAsType(MapTag.class);
for (Map.Entry<StringHolder, ObjectTag> entry : glowMap.map.entrySet()) {
if (EnumHelper.get(Side.class).valuesMapLower.containsKey(entry.getKey().str)) {
Side side = Side.valueOf(entry.getKey().toString().toUpperCase());
if (EnumHelper.get(DyeColor.class).valuesMapLower.containsKey(entry.getValue().asElement().asLowerString())) {
DyeColor color = DyeColor.valueOf(entry.getValue().asElement().asLowerString().toUpperCase());
sign.getSide(side).setColor(color);
} else {
mechanism.echoError("Unknown dye color " + entry.getValue());
}
} else {
mechanism.echoError("Unknown sign side " + entry.getKey());
}
}
sign.update();
}
}
}

// <--[mechanism]
// @object LocationTag
// @name sign_waxed
// @input ElementTag(Boolean)
// @description
// Changes whether the sign at the location is waxed.
// @tags
// <LocationTag.sign_waxed>
// -->
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) {
if (mechanism.matches("sign_waxed") && mechanism.requireBoolean()) {
BlockState state = getBlockState();
if (!(state instanceof Sign sign)) {
mechanism.echoError("'sign_waxed' mechanism can only be called on Sign blocks.");
} else {
sign.setWaxed(mechanism.getValue().asBoolean());
sign.update();
}
}
}

// <--[mechanism]
// @object LocationTag
// @name structure_block_data
Expand Down
Loading