diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java index 551b95f1fc8..e055523f283 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -1550,6 +1550,20 @@ public String toVariableNameString(WorldBorder border) { .changer(DefaultChangers.entityChanger) ); + Classes.registerClass(new ClassInfo<>(ItemFrame.class, "itemframe") + .user("item ?frames?") + .name("Item Frame") + .description("Represents the itemframe entity. This classinfo is used to manipulate settings of itemframes in syntaxes.") + .since("INSERT VERSION") + .defaultExpression(new EventValueExpression<>(ItemFrame.class))); + + Classes.registerClass(new EnumClassInfo<>(Rotation.class, "rotation", "rotations") + .user("rotations?") + .name("Rotation") + .description( + "Specify a rotation based orientation, like that on a clock. Used in item frames.", + "It represents how something is viewed, as opposed to cardinal directions.") + .since("INSERT VERSION")); } } diff --git a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java index ee44ad09dd2..77af155270d 100644 --- a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java @@ -1,5 +1,13 @@ package ch.njol.skript.classes.data; +import java.io.StreamCorruptedException; +import java.util.Iterator; +import java.util.Locale; +import java.util.regex.Pattern; + +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; import ch.njol.skript.ScriptLoader; import ch.njol.skript.Skript; import ch.njol.skript.aliases.Aliases; @@ -25,9 +33,6 @@ import ch.njol.skript.util.visual.VisualEffect; import ch.njol.skript.util.visual.VisualEffects; import ch.njol.yggdrasil.Fields; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.lang.script.Script; import org.skriptlang.skript.lang.util.SkriptQueue; @@ -35,13 +40,9 @@ import java.io.File; import java.io.NotSerializableException; -import java.io.StreamCorruptedException; import java.nio.file.Path; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.Locale; -import java.util.regex.Pattern; @SuppressWarnings("rawtypes") public class SkriptClasses { diff --git a/src/main/java/ch/njol/skript/effects/EffRotate.java b/src/main/java/ch/njol/skript/effects/EffRotate.java new file mode 100644 index 00000000000..230d855bb94 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffRotate.java @@ -0,0 +1,115 @@ +package ch.njol.skript.effects; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.bukkit.Rotation; +import org.bukkit.entity.ItemFrame; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; + +@Name("Rotate") +@Description("Rotate rotations or itemframes an amount of times based on the provided rotation.") +@Examples({ + "rotate the event-item frame clockwise 2 times", + "rotate the event-item frame by 225 degrees" +}) +@Since("INSERT VERSION") +public class EffRotate extends Effect { + + static { + Skript.registerEffect(EffRotate.class, "rotate %~rotations% [:counter] clockwise %*number% times"); + Skript.registerEffect(EffRotate.class, "rotate %itemframes% [by] %rotation%"); + } + + private @Nullable Expression itemFrames; + private Expression rotations; + private boolean counter; + private int amount; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + rotations = (Expression) exprs[matchedPattern ^ 0]; + if (matchedPattern == 0) { + amount = Optional.ofNullable(((Literal) exprs[1])) + .map(Literal::getSingle) + .map(Number::intValue) + .orElse(1); + } else { + itemFrames = (Expression) exprs[0]; + } + counter = parseResult.hasTag("counter"); + return true; + } + + @Override + protected void execute(Event event) { + if (itemFrames != null) { + Rotation rotation = rotations.getOptionalSingle(event).orElse(Rotation.NONE); + if (rotation == Rotation.NONE) + return; + itemFrames.stream(event).forEach(itemFrame -> + itemFrame.setRotation(rotate(itemFrame.getRotation(), rotation))); + return; + } + rotations.change(event, rotations.stream(event).map(this::rotate).toArray(Rotation[]::new), ChangeMode.SET); + } + + /** + * The amount of times to rotate clockwise to get to the matched degree. + */ + private static final Map order = new HashMap<>(); + + static { + order.put(Rotation.CLOCKWISE_45, 1); + order.put(Rotation.CLOCKWISE, 2); + order.put(Rotation.CLOCKWISE_135, 3); + order.put(Rotation.FLIPPED, 4); + order.put(Rotation.FLIPPED_45, 5); + order.put(Rotation.COUNTER_CLOCKWISE, 6); + order.put(Rotation.COUNTER_CLOCKWISE_45, 7); + } + + private Rotation rotate(Rotation relative, Rotation rotation) { + for (int i = 0; i < order.get(relative); i++) + rotation.rotateClockwise(); + return rotation; + } + + private Rotation rotate(Rotation rotation) { + for (int i = 0; i < amount; i++) { + if (counter) { + rotation.rotateCounterClockwise(); + } else { + rotation.rotateClockwise(); + } + } + return rotation; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String string; + if (itemFrames != null) { + string = "rotate " + itemFrames.toString(event, debug) + " " + rotations.toString(event, debug); + } else { + string = "rotate " + rotations.toString(event, debug) + (counter ? " counter " : "") + " clockwise"; + } + return string + " " + amount + " time" + (amount <= 1 ? "" : "s"); + } + +} diff --git a/src/main/java/ch/njol/skript/entity/ItemFrameData.java b/src/main/java/ch/njol/skript/entity/ItemFrameData.java new file mode 100644 index 00000000000..8b482ba867f --- /dev/null +++ b/src/main/java/ch/njol/skript/entity/ItemFrameData.java @@ -0,0 +1,113 @@ +package ch.njol.skript.entity; + +import org.bukkit.Rotation; +import org.bukkit.entity.ItemFrame; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.localization.Noun; +import ch.njol.skript.registrations.Classes; + +public class ItemFrameData extends EntityData { + + static { + EntityData.register(ItemFrameData.class, "item frame", ItemFrame.class, "item frame"); + } + + private @Nullable ItemType type; + + private Rotation rotation = Rotation.NONE; + + public ItemFrameData() {} + + public ItemFrameData(@Nullable ItemType type, @Nullable Rotation rotation) { + this.rotation = rotation; + this.type = type; + } + + @Override + protected boolean init(Literal[] exprs, int matchedPattern, ParseResult parseResult) { + if (exprs[0] != null) + type = (ItemType) exprs[0].getSingle(); + if (exprs[1] != null) + rotation = (Rotation) exprs[1].getSingle(); + return true; + } + + @Override + protected boolean init(@Nullable Class entityClass, @Nullable ItemFrame itemframe) { + if (itemframe != null) { + ItemStack item = itemframe.getItem(); + type = new ItemType(item); + rotation = itemframe.getRotation(); + } + return true; + } + + @Override + protected boolean match(ItemFrame itemframe) { + if (type == null) + return true; + return type.isOfType(itemframe.getItem()) && itemframe.getRotation() == rotation; + } + + @Override + public void set(ItemFrame itemframe) { + assert type != null; + ItemStack item = type.getItem().getRandom(); + if (item != null) + itemframe.setItem(item); + itemframe.setRotation(rotation); + } + + @Override + public boolean isSupertypeOf(EntityData entityData) { + if (!(entityData instanceof ItemFrameData)) + return false; + ItemFrameData itemFrameData = (ItemFrameData) entityData; + if (type != null) + return itemFrameData.type != null && type.equals(itemFrameData.type) && rotation == itemFrameData.rotation; + return true; + } + + @Override + public Class getType() { + return ItemFrame.class; + } + + @Override + public EntityData getSuperType() { + return new ItemFrameData(type, rotation); + } + + @Override + public String toString(int flags) { + if (type == null) + return super.toString(flags); + StringBuilder builder = new StringBuilder(); + builder.append(Noun.getArticleWithSpace(type.getTypes().get(0).getGender(), flags)); + builder.append("item frame " + type == null ? "" : "of " + type.toString(flags)); + builder.append("rotated " + Classes.toString(rotation)); + return builder.toString(); + } + + @Override + protected boolean equals_i(EntityData entityData) { + if (!(entityData instanceof ItemFrameData other)) + return false; + return type == null ? true : type.equals(other.type) && rotation == other.rotation; + } + + @Override + protected int hashCode_i() { + int prime = 31; + int result = 1; + result = prime * result + (type == null ? 0 : type.hashCode()); + result = prime * result + rotation.hashCode(); + return result; + } + +} diff --git a/src/main/java/ch/njol/skript/util/slot/ItemFrameSlot.java b/src/main/java/ch/njol/skript/util/slot/ItemFrameSlot.java index a5140d1dad4..162f48e0945 100644 --- a/src/main/java/ch/njol/skript/util/slot/ItemFrameSlot.java +++ b/src/main/java/ch/njol/skript/util/slot/ItemFrameSlot.java @@ -11,9 +11,9 @@ * Represents contents of an item frame. */ public class ItemFrameSlot extends Slot { - + private ItemFrame frame; - + public ItemFrameSlot(ItemFrame frame) { this.frame = frame; } @@ -28,25 +28,25 @@ public ItemStack getItem() { public void setItem(@Nullable ItemStack item) { frame.setItem(item); } - + @Override public int getAmount() { return 1; } - + @Override public void setAmount(int amount) {} - + @Override - public boolean isSameSlot(Slot o) { - if (o instanceof ItemFrameSlot) // Same item frame - return ((ItemFrameSlot) o).frame.equals(frame); + public boolean isSameSlot(Slot slot) { + if (slot instanceof ItemFrameSlot) // Same item frame + return ((ItemFrameSlot) slot).frame.equals(frame); return false; } @Override - public String toString(@Nullable Event e, boolean debug) { + public String toString(@Nullable Event event, boolean debug) { return Classes.toString(getItem()); } - + } diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index a2f3fbfc54c..374ce911509 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -650,7 +650,7 @@ entities: pattern: lightning bolt(|1¦s) item frame: name: item frame¦s @an - pattern: item[ ]frame(|1¦s) + pattern: item[ ]frame(|1¦s) [(with|of) %-itemtype%] [[(with rotation|rotated)] %-rotation%] magma cube: name: magma cube¦s pattern: magma (cube|slime)(|1¦s) @@ -2548,6 +2548,17 @@ banner pattern types: half_vertical_mirror: vertical half mirror banner pattern half_horizontal_mirror: horizontal half mirror banner pattern +# -- Rotations -- +rotations: + clockwise: clockwise, clockwise by 90 degrees, clockwise 90 degrees, 90 degrees + clockwise_135: clockwise 135, clockwise by 135 degrees, 135 degrees + clockwise_45: clockwise 45, clockwise by 45 degrees, 45 degrees + counter_clockwise: counter clockwise, counter clockwise by 90 degrees, counter clockwise 90 degrees, 270 degrees + counter_clockwise_45: counter clockwise 45, counter clockwise by 45 degrees, 315 degrees + flipped: flipped, flipped upside-down, flipped upside down, 180 degrees + flipped_45: flipped 45, flipped upside-down by 45 degrees, 225 degrees + none: none, nothing, no rotation, not rotated, 360 degrees + # -- Input Keys -- input keys: forward: forward movement key, forward key @@ -2659,6 +2670,8 @@ types: bannerpatterntype: banner pattern type¦s @a bannerpattern: banner pattern¦s @a vehicle: vehicle¦s @a + itemframe: item frame¦s @an + rotation: rotation¦s @a # Skript weathertype: weather type¦s @a