diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java
index 3755525edb1..2703ef61c7d 100644
--- a/src/main/java/ch/njol/skript/Skript.java
+++ b/src/main/java/ch/njol/skript/Skript.java
@@ -556,6 +556,7 @@ public void onEnable() {
try {
getAddonInstance().loadClasses("ch.njol.skript",
"conditions", "effects", "events", "expressions", "entity", "sections", "structures");
+ getAddonInstance().loadClasses("org.skriptlang.skript", "elements");
} catch (final Exception e) {
exception(e, "Could not load required .class files: " + e.getLocalizedMessage());
setEnabled(false);
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 6da8522d035..3487dcf4270 100644
--- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
+++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
@@ -39,6 +39,7 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
+import org.bukkit.Rotation;
import org.bukkit.Registry;
import org.bukkit.SoundCategory;
import org.bukkit.World;
@@ -55,6 +56,7 @@
import org.bukkit.entity.Cat;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
+import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Panda.Gene;
import org.bukkit.entity.Player;
@@ -100,6 +102,7 @@
import ch.njol.skript.localization.Language;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.util.BlockUtils;
+import ch.njol.skript.util.EnchantmentType;
import ch.njol.skript.util.PotionEffectUtils;
import ch.njol.skript.util.StringMode;
import ch.njol.util.StringUtils;
@@ -1525,6 +1528,14 @@ public String toVariableNameString(EnchantmentOffer eo) {
.name("Transform Reason")
.description("Represents a transform reason of an entity transform event.")
.since("2.8.0"));
+
+ 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)));
+
}
}
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 6f92502cd2a..cf5f78dc777 100644
--- a/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java
+++ b/src/main/java/ch/njol/skript/classes/data/SkriptClasses.java
@@ -24,6 +24,7 @@
import java.util.regex.Pattern;
import org.bukkit.Material;
+import org.bukkit.Rotation;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;
@@ -36,6 +37,7 @@
import ch.njol.skript.bukkitutil.ItemUtils;
import ch.njol.skript.classes.Changer;
import ch.njol.skript.classes.ClassInfo;
+import ch.njol.skript.classes.EnumClassInfo;
import ch.njol.skript.classes.EnumSerializer;
import ch.njol.skript.classes.Parser;
import ch.njol.skript.classes.Serializer;
@@ -691,6 +693,23 @@ public String toVariableNameString(VisualEffect e) {
.since("2.5")
.serializer(new YggdrasilSerializer())
);
+
+ /**
+ * TODO fix loading structure for allowing classinfos used in the default.lang file.
+ *
+ * Due to the loading structure of Skript. Aliases load the default.lang file.
+ * ClassInfos that are used within that file need to be registered in this class.
+ * SkriptClasses.class loads before loading Aliases.
+ *
+ * So the bukkit classes below must be present here.
+ */
+ 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/effects/EffRotate.java b/src/main/java/ch/njol/skript/effects/EffRotate.java
new file mode 100644
index 00000000000..46c4df75b5b
--- /dev/null
+++ b/src/main/java/ch/njol/skript/effects/EffRotate.java
@@ -0,0 +1,134 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript 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
+ * (at your option) any later version.
+ *
+ * Skript 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 Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+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.eclipse.jdt.annotation.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%");
+ }
+
+ @Nullable
+ private 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..8909f5876b9
--- /dev/null
+++ b/src/main/java/ch/njol/skript/entity/ItemFrameData.java
@@ -0,0 +1,132 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript 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
+ * (at your option) any later version.
+ *
+ * Skript 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 Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+package ch.njol.skript.entity;
+
+import org.bukkit.Rotation;
+import org.bukkit.entity.ItemFrame;
+import org.bukkit.inventory.ItemStack;
+import org.eclipse.jdt.annotation.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");
+ }
+
+ @Nullable
+ private 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 extends ItemFrame> c, @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 extends ItemFrame> 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))
+ return false;
+ return type == null ? true : type.equals(((ItemFrameData) entityData).type) && rotation == ((ItemFrameData) entityData).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 024fb9d9ca4..56292850441 100644
--- a/src/main/java/ch/njol/skript/util/slot/ItemFrameSlot.java
+++ b/src/main/java/ch/njol/skript/util/slot/ItemFrameSlot.java
@@ -29,9 +29,9 @@
* Represents contents of an item frame.
*/
public class ItemFrameSlot extends Slot {
-
+
private ItemFrame frame;
-
+
public ItemFrameSlot(ItemFrame frame) {
this.frame = frame;
}
@@ -46,25 +46,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/java/ch/njol/skript/expressions/ExprItemFrameSlot.java b/src/main/java/org/skriptlang/skript/elements/expressions/itemframes/ExprItemFrameSlot.java
similarity index 72%
rename from src/main/java/ch/njol/skript/expressions/ExprItemFrameSlot.java
rename to src/main/java/org/skriptlang/skript/elements/expressions/itemframes/ExprItemFrameSlot.java
index f5d42ac3260..fa220727a1b 100644
--- a/src/main/java/ch/njol/skript/expressions/ExprItemFrameSlot.java
+++ b/src/main/java/org/skriptlang/skript/elements/expressions/itemframes/ExprItemFrameSlot.java
@@ -16,7 +16,7 @@
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
-package ch.njol.skript.expressions;
+package org.skriptlang.skript.elements.expressions.itemframes;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
@@ -37,39 +37,44 @@
import ch.njol.skript.util.slot.ThrowableProjectileSlot;
@Name("Item of an Entity")
-@Description("An item associated with an entity. For dropped item entities, it gets, obviously, the item that was dropped. "
- + "For item frames, the item inside the frame is returned. For throwable projectiles (snowballs, enderpearls etc.),"
- + "it gets the displayed item. Other entities do not have items associated with them.")
-@Examples("")
+@Description({
+ "An item associated with an entity. For dropped item entities, it gets the item that was dropped.",
+ "For item frames, the item inside the frame is returned.",
+ "For throwable projectiles (snowballs, enderpearls etc.) it gets the displayed item.",
+ "Other entities do not have items associated with them."
+})
+@Examples("set item of target entity to stone")
@Since("2.2-dev35, 2.2-dev36 (improved), 2.5.2 (throwable projectiles)")
@RequiredPlugins("Minecraft 1.15.2+ (throwable projectiles)")
public class ExprItemFrameSlot extends SimplePropertyExpression {
-
+
private static final boolean PROJECTILE_SUPPORT = Skript.classExists("org.bukkit.entity.ThrowableProjectile");
-
+
static {
register(ExprItemFrameSlot.class, Slot.class, "item", "entities");
}
-
+
@Override
@Nullable
- public Slot convert(Entity e) {
- if (e instanceof ItemFrame)
- return new ItemFrameSlot((ItemFrame) e);
- else if (e instanceof Item)
- return new DroppedItemSlot((Item) e);
- else if (PROJECTILE_SUPPORT && e instanceof ThrowableProjectile)
- return new ThrowableProjectileSlot((ThrowableProjectile) e);
+ public Slot convert(Entity entity) {
+ if (entity instanceof ItemFrame) {
+ return new ItemFrameSlot((ItemFrame) entity);
+ } else if (entity instanceof Item) {
+ return new DroppedItemSlot((Item) entity);
+ } else if (PROJECTILE_SUPPORT && entity instanceof ThrowableProjectile) {
+ return new ThrowableProjectileSlot((ThrowableProjectile) entity);
+ }
return null; // Other entities don't have associated items
}
- @Override
- protected String getPropertyName() {
- return "item of entity";
- }
-
@Override
public Class extends Slot> getReturnType() {
return Slot.class;
}
+
+ @Override
+ protected String getPropertyName() {
+ return "item of entity";
+ }
+
}
diff --git a/src/main/java/org/skriptlang/skript/elements/expressions/itemframes/package-info.java b/src/main/java/org/skriptlang/skript/elements/expressions/itemframes/package-info.java
new file mode 100644
index 00000000000..a45dd0da066
--- /dev/null
+++ b/src/main/java/org/skriptlang/skript/elements/expressions/itemframes/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * This file is part of Skript.
+ *
+ * Skript 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
+ * (at your option) any later version.
+ *
+ * Skript 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 Skript. If not, see .
+ *
+ * Copyright Peter Güttinger, SkriptLang team and contributors
+ */
+@NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD})
+package org.skriptlang.skript.elements.expressions.itemframes;
+
+import org.eclipse.jdt.annotation.DefaultLocation;
+import org.eclipse.jdt.annotation.NonNullByDefault;
diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang
index 3e4bc87b7a4..9350d4f73da 100644
--- a/src/main/resources/lang/default.lang
+++ b/src/main/resources/lang/default.lang
@@ -626,7 +626,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)
@@ -2273,6 +2273,17 @@ transform reasons:
unknown: unknown
infection: infection, villager infection
+# -- 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
+
# -- Boolean --
boolean:
true:
@@ -2352,6 +2363,8 @@ types:
quitreason: quit reason¦s @a
inventoryclosereason: inventory close reason¦s @an
transformreason: transform reason¦s @a
+ itemframe: item frame¦s @an
+ rotation: rotation¦s @a
# Skript
weathertype: weather type¦s @a