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 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 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 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