From 354fd114567c52dbcc20206b6f59a91240cf788d Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sat, 1 Nov 2025 01:05:33 -0400 Subject: [PATCH 1/6] Initial Commit --- src/main/java/ch/njol/skript/Skript.java | 4 +- .../bukkit/mannequin/MannequinData.java | 81 +++++++++ .../bukkit/mannequin/MannequinModule.java | 35 ++++ .../elements/CondMannequinImmovable.java | 59 +++++++ .../elements/CondMannequinParts.java | 118 +++++++++++++ .../elements/EffMannequinImmovable.java | 68 ++++++++ .../mannequin/elements/EffMannequinParts.java | 158 ++++++++++++++++++ .../mannequin/elements/ExprMannequinDesc.java | 94 +++++++++++ .../mannequin/elements/ExprMannequinSkin.java | 118 +++++++++++++ src/main/resources/lang/default.lang | 11 +- src/test/skript/tests/misc/EntityData.sk | 5 + .../syntaxes/effects/EffMannequinImmovable.sk | 8 + .../syntaxes/effects/EffMannequinParts.sk | 77 +++++++++ .../syntaxes/expressions/ExprMannequinDesc.sk | 12 ++ .../syntaxes/expressions/ExprMannequinSkin.sk | 13 ++ 15 files changed, 857 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java create mode 100644 src/test/skript/tests/syntaxes/effects/EffMannequinImmovable.sk create mode 100644 src/test/skript/tests/syntaxes/effects/EffMannequinParts.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprMannequinDesc.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprMannequinSkin.sk diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index e38c523eb62..5af27e9bfd9 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -101,6 +101,7 @@ import org.skriptlang.skript.bukkit.itemcomponents.ItemComponentModule; import org.skriptlang.skript.bukkit.log.runtime.BukkitRuntimeErrorConsumer; import org.skriptlang.skript.bukkit.loottables.LootTableModule; +import org.skriptlang.skript.bukkit.mannequin.MannequinModule; import org.skriptlang.skript.bukkit.registration.BukkitRegistryKeys; import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos; import org.skriptlang.skript.bukkit.tags.TagModule; @@ -599,7 +600,8 @@ public void onEnable() { new DamageSourceModule(), new ItemComponentModule(), new BrewingModule(), - new CommonModule() + new CommonModule(), + new MannequinModule() ); } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java new file mode 100644 index 00000000000..2843f95af55 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java @@ -0,0 +1,81 @@ +package org.skriptlang.skript.bukkit.mannequin; + +import ch.njol.skript.entity.EntityData; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.entity.Mannequin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class MannequinData extends EntityData { + + public static void register() { + register(MannequinData.class, "mannequin", Mannequin.class, 0, "mannequin"); + } + + private Kleenean immovable = Kleenean.UNKNOWN; + + public MannequinData() {} + + public MannequinData(@Nullable Kleenean immovable) { + this.immovable = immovable == null ? Kleenean.UNKNOWN : immovable; + } + + @Override + protected boolean init(Literal[] exprs, int matchedCodeName, int matchedPattern, ParseResult parseResult) { + if (matchedPattern == 1) { + immovable = Kleenean.TRUE; + } else if (matchedPattern == 2) { + immovable = Kleenean.FALSE; + } + return true; + } + + @Override + protected boolean init(@Nullable Class entityClass, @Nullable Mannequin mannequin) { + if (mannequin != null) + immovable = Kleenean.get(mannequin.isImmovable()); + return true; + } + + @Override + public void set(Mannequin mannequin) { + mannequin.setImmovable(immovable.isTrue()); + } + + @Override + protected boolean match(Mannequin mannequin) { + return kleeneanMatch(immovable, mannequin.isImmovable()); + } + + @Override + public Class getType() { + return Mannequin.class; + } + + @Override + public @NotNull EntityData getSuperType() { + return new MannequinData(); + } + + @Override + protected int hashCode_i() { + return immovable.hashCode(); + } + + @Override + protected boolean equals_i(EntityData entityData) { + if (!(entityData instanceof MannequinData other)) + return false; + return immovable == other.immovable; + } + + @Override + public boolean isSupertypeOf(EntityData entityData) { + if (!(entityData instanceof MannequinData other)) + return false; + return kleeneanMatch(immovable, other.immovable); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java new file mode 100644 index 00000000000..773e495b1b1 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java @@ -0,0 +1,35 @@ +package org.skriptlang.skript.bukkit.mannequin; + +import ch.njol.skript.Skript; +import org.skriptlang.skript.addon.AddonModule; +import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.bukkit.mannequin.elements.CondMannequinImmovable; +import org.skriptlang.skript.bukkit.mannequin.elements.CondMannequinParts; +import org.skriptlang.skript.bukkit.mannequin.elements.EffMannequinImmovable; +import org.skriptlang.skript.bukkit.mannequin.elements.EffMannequinParts; +import org.skriptlang.skript.bukkit.mannequin.elements.ExprMannequinDesc; +import org.skriptlang.skript.bukkit.mannequin.elements.ExprMannequinSkin; +import org.skriptlang.skript.registration.SyntaxRegistry; + +public class MannequinModule implements AddonModule { + + @Override + public boolean canLoad(SkriptAddon addon) { + return Skript.classExists("org.bukkit.entity.Mannequin"); + } + + @Override + public void load(SkriptAddon addon) { + SyntaxRegistry registry = addon.syntaxRegistry(); + + CondMannequinParts.register(registry); + CondMannequinImmovable.register(registry); + EffMannequinParts.register(registry); + EffMannequinImmovable.register(registry); + ExprMannequinDesc.register(registry); + ExprMannequinSkin.register(registry); + + MannequinData.register(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java new file mode 100644 index 00000000000..2cd32915808 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java @@ -0,0 +1,59 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Mannequin is Immovable") +@Description("Whether a mannequin is immovable or movable.") +@Example(""" + if last spawned mannequin is movable: + make last spawned mannequin immovable + """) +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class CondMannequinImmovable extends PropertyCondition { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.CONDITION, + infoBuilder( + CondMannequinImmovable.class, + PropertyType.BE, + "[:im]movable", + "entities" + ).supplier(CondMannequinImmovable::new) + .build() + ); + } + + private boolean immovable; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + immovable = parseResult.hasTag("im"); + return super.init(expressions, matchedPattern, isDelayed, parseResult); + } + + @Override + public boolean check(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return false; + return mannequin.isImmovable() == immovable; + } + + @Override + protected String getPropertyName() { + return immovable ? "immovable" : "movable"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java new file mode 100644 index 00000000000..92539f638b5 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java @@ -0,0 +1,118 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.util.Patterns; +import ch.njol.util.Kleenean; +import com.destroystokyo.paper.SkinParts; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.mannequin.elements.EffMannequinParts.MannequinPart; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; + +import java.util.function.Function; + +@Name("Mannequin Skin Part is Enabled") +@Description("Whether a specific skin part of a mannequin is enabled or disabled.") +@Example("") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class CondMannequinParts extends Condition { + + private static final Patterns PATTERNS = new Patterns<>(new Object[][]{ + getPattern(MannequinPart.CAPE), + getPattern(MannequinPart.HAT), + getPattern(MannequinPart.JACKET), + getPattern(MannequinPart.LEFT_PANTS), + getPattern(MannequinPart.LEFT_SLEEVE), + getPattern(MannequinPart.RIGHT_PANTS), + getPattern(MannequinPart.RIGHT_SLEEVE), + getPattern(MannequinPart.PANTS), + getPattern(MannequinPart.SLEEVES), + getPattern(MannequinPart.ALL) + }); + + private static Object[] getPattern(MannequinPart part) { + String pattern; + if (part == MannequinPart.ALL) { + pattern = "all [[of] the] mannequin skin parts of %entities% are ((enabled|showing|revealed)|disable:(disabled|hidden))"; + } else { + pattern = "[the] mannequin " + part.part + " [skin] [part[s]] of %entities% (is|are) ((enabled|showing|revealed)|disable:(disabled|hidden))"; + } + return new Object[] {pattern, part}; + } + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.CONDITION, + SyntaxInfo.builder(CondMannequinParts.class) + .addPatterns(PATTERNS.getPatterns()) + .supplier(CondMannequinParts::new) + .build() + ); + } + + private Expression entities; + private boolean enable; + private MannequinPart mannequinPart; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + entities = (Expression) exprs[0]; + enable = !parseResult.hasTag("disable"); + mannequinPart = PATTERNS.getInfo(matchedPattern); + return true; + } + + @Override + public boolean check(Event event) { + Function checker = switch (mannequinPart) { + case CAPE -> SkinParts::hasCapeEnabled; + case HAT -> SkinParts::hasHatsEnabled; + case JACKET -> SkinParts::hasJacketEnabled; + case LEFT_PANTS -> SkinParts::hasLeftPantsEnabled; + case LEFT_SLEEVE -> SkinParts::hasLeftSleeveEnabled; + case RIGHT_PANTS -> SkinParts::hasRightPantsEnabled; + case RIGHT_SLEEVE -> SkinParts::hasRightSleeveEnabled; + case PANTS -> skin -> skin.hasRightPantsEnabled() && skin.hasRightPantsEnabled(); + case SLEEVES -> skin -> skin.hasRightSleeveEnabled() && skin.hasLeftSleeveEnabled(); + case ALL -> skin -> skin.hasCapeEnabled() && skin.hasHatsEnabled() && skin.hasJacketEnabled() + && skin.hasLeftPantsEnabled() && skin.hasLeftSleeveEnabled() && skin.hasRightPantsEnabled() + && skin.hasRightSleeveEnabled(); + }; + return entities.check(event, entity -> { + if (!(entity instanceof Mannequin mannequin)) + return false; + return checker.apply(mannequin.getSkinParts()) == enable; + }); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + if (mannequinPart == MannequinPart.ALL) { + builder.append("all of the mannequin skin parts"); + } else { + builder.append("the mannequin", mannequinPart.part, "skin part"); + } + builder.append("of", entities, "are"); + if (enable) { + builder.append("enabled"); + } else { + builder.append("disabled"); + } + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java new file mode 100644 index 00000000000..118368d6786 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java @@ -0,0 +1,68 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.util.Kleenean; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Make Mannequin Immovable") +@Description("Whether a mannequin should be immovable or movable.") +@Example(""" + if last spawned mannequin is movable: + make last spawned mannequin immovable + """) +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class EffMannequinImmovable extends Effect { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EFFECT, + SyntaxInfo.builder(EffMannequinImmovable.class) + .addPatterns("make %entities% [:im]movable") + .supplier(EffMannequinImmovable::new) + .build() + ); + } + + private Expression entities; + private boolean immovable; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + entities = (Expression) exprs[0]; + immovable = parseResult.hasTag("im"); + return true; + } + + @Override + protected void execute(Event event) { + for (Entity entity : entities.getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + mannequin.setImmovable(immovable); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String move = immovable ? "immovable" : "movable"; + return new SyntaxStringBuilder(event, debug) + .append("make", entities, move) + .toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java new file mode 100644 index 00000000000..878c5e267ee --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java @@ -0,0 +1,158 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.util.Patterns; +import ch.njol.util.Kleenean; +import com.destroystokyo.paper.SkinParts; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; + +import java.util.function.Consumer; + +@Name("Mannequin Skin Parts") +@Description("Enable or disable a skin part of a mannequin.") +@Example("enable the mannequin cape for {_mannequin}") +@Example("show the mannequin hat skin part for {_mannequin}") +@Example("reveal the mannequin jacket for {_mannequin}") +@Example("disable the mannequin left pants skin for {_mannequin}") +@Example("hide the mannequin left sleeve for {_mannequin}") +@Example("enable all of the mannequin skin parts for {_mannequin}") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class EffMannequinParts extends Effect { + + private static final Patterns PATTERNS = new Patterns<>(new Object[][]{ + getPattern(MannequinPart.CAPE), + getPattern(MannequinPart.HAT), + getPattern(MannequinPart.JACKET), + getPattern(MannequinPart.LEFT_PANTS), + getPattern(MannequinPart.LEFT_SLEEVE), + getPattern(MannequinPart.RIGHT_PANTS), + getPattern(MannequinPart.RIGHT_SLEEVE), + getPattern(MannequinPart.PANTS), + getPattern(MannequinPart.SLEEVES), + getPattern(MannequinPart.ALL) + }); + + private static Object[] getPattern(MannequinPart part) { + String pattern; + if (part == MannequinPart.ALL) { + pattern = "((enable|show|reveal)|disable:(disable|hide)) all [[of] the] mannequin skin parts (of|for) %entities%"; + } else { + pattern = "((enable|show|reveal)|disable:(disable|hide)) [the] mannequin " + part.part + " [skin [part[s]]] (of|for) %entities%"; + } + return new Object[] {pattern, part}; + } + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EFFECT, + SyntaxInfo.builder(EffMannequinParts.class) + .addPatterns(PATTERNS.getPatterns()) + .supplier(EffMannequinParts::new) + .build() + ); + } + + public enum MannequinPart { + CAPE("cape"), + HAT("hat"), + JACKET("jacket"), + LEFT_PANTS("left pants"), + LEFT_SLEEVE("left sleeve"), + RIGHT_PANTS("right pants"), + RIGHT_SLEEVE("right sleeve"), + PANTS("pants"), + SLEEVES("sleeves"), + ALL("all") + ; + + public final String part; + + MannequinPart(String part) { + this.part = part; + } + + } + + private Expression entities; + private boolean enable; + private MannequinPart mannequinPart; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + entities = (Expression) exprs[0]; + enable = !parseResult.hasTag("disable"); + mannequinPart = PATTERNS.getInfo(matchedPattern); + return true; + } + + @Override + protected void execute(Event event) { + Consumer changer = switch (mannequinPart) { + case CAPE -> skin -> skin.setCapeEnabled(enable); + case HAT -> skin -> skin.setHatsEnabled(enable); + case JACKET -> skin -> skin.setJacketEnabled(enable); + case LEFT_PANTS -> skin -> skin.setLeftPantsEnabled(enable); + case LEFT_SLEEVE -> skin -> skin.setLeftSleeveEnabled(enable); + case RIGHT_PANTS -> skin -> skin.setRightPantsEnabled(enable); + case RIGHT_SLEEVE -> skin -> skin.setRightSleeveEnabled(enable); + case PANTS -> skin -> { + skin.setRightPantsEnabled(enable); + skin.setLeftPantsEnabled(enable); + }; + case SLEEVES -> skin -> { + skin.setRightSleeveEnabled(enable); + skin.setLeftSleeveEnabled(enable); + }; + case ALL -> skin -> { + skin.setCapeEnabled(enable); + skin.setHatsEnabled(enable); + skin.setJacketEnabled(enable); + skin.setLeftPantsEnabled(enable); + skin.setLeftSleeveEnabled(enable); + skin.setRightPantsEnabled(enable); + skin.setRightSleeveEnabled(enable); + }; + }; + + for (Entity entity : entities.getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + SkinParts.Mutable skinParts = mannequin.getSkinParts(); + changer.accept(skinParts); + mannequin.setSkinParts(skinParts); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + if (enable) { + builder.append("enable"); + } else { + builder.append("disable"); + } + if (mannequinPart == MannequinPart.ALL) { + builder.append("all of the mannequin skin parts"); + } else { + builder.append("the mannequin", mannequinPart.part); + } + builder.append("of", entities); + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java new file mode 100644 index 00000000000..2465c45720f --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java @@ -0,0 +1,94 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Mannequin Description") +@Description(""" + The description of a mannequin. + The description is displayed below the display name of the mannequin. + If the display name of the mannequin is not set, the description will not show. + The default description of a mannequin is "NPC". + """) +@Example("set the mannequin description of {_mannequin} to \"Shop\"") +@Example("clear the mannequin description of last spawned mannequin") +@Example("reset the mannequin description of last spawned mannequin") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class ExprMannequinDesc extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprMannequinDesc.class, + String.class, + "mannequin description", + "entities", + false + ).supplier(ExprMannequinDesc::new) + .build() + ); + } + + @Override + public @Nullable String convert(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return null; + Component desc = mannequin.getDescription(); + if (desc == null) + return null; + // TODO: Use Pickle's Adventure Component API + return LegacyComponentSerializer.legacyAmpersand().serialize(desc); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, RESET -> CollectionUtils.array(String.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Component component = null; + if (mode == ChangeMode.SET) { + assert delta != null; + String string = (String) delta[0]; + component = Component.text(string); + } else if (mode == ChangeMode.RESET) { + component = Mannequin.defaultDescription(); + } + + for (Entity entity : getExpr().getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + mannequin.setDescription(component); + } + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "mannequin description"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java new file mode 100644 index 00000000000..fe9db7be341 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java @@ -0,0 +1,118 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import com.destroystokyo.paper.profile.PlayerProfile; +import com.destroystokyo.paper.profile.ProfileProperty; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile.Builder; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.registration.SyntaxRegistry; + +import java.util.UUID; + +@Name("Mannequin Skin") +@Description(""" + The skin of a mannequin. + The skin can be set to an offlineplayer or a texture value of a skin. + """) +@Example("set the mannequin skin of {_mannequin} to offlineplayer(\"Notch\")") +@Example(""" + set the mannequin skin of last spawned mannequin to "e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW\ + 5lY3JhZnQubmV0L3RleHR1cmUvYWJjNzNlN2VlNzA4ZTQ3NjU4YWY3YzMzMTZkY2VkNzk5NDUyNTg3NDg1NjM5ODA4ZDQ3OTVkMjNmYzY4NDU1MCJ9fX0=" + """) +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class ExprMannequinSkin extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprMannequinSkin.class, + Object.class, + "mannequin skin", + "entities", + false + ).supplier(ExprMannequinSkin::new) + .build() + ); + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public @Nullable Object convert(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return null; + ResolvableProfile profile = mannequin.getProfile(); + UUID uuid = profile.uuid(); + if (uuid != null) + return Bukkit.getOfflinePlayer(uuid); + String name = profile.name(); + if (name != null) + return Bukkit.getOfflinePlayer(name); + for (ProfileProperty property : profile.properties()) { + if (property.getName().equals("textures")) + return property.getValue(); + } + return null; + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.RESET) + return CollectionUtils.array(OfflinePlayer.class, String.class); + return null; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + ResolvableProfile profile = Mannequin.defaultProfile(); + if (delta != null) { + if (delta[0] instanceof OfflinePlayer player) { + PlayerProfile playerProfile = player.getPlayerProfile(); + playerProfile.complete(); + profile = ResolvableProfile.resolvableProfile(playerProfile); + } else if (delta[0] instanceof String string) { + Builder builder = ResolvableProfile.resolvableProfile(); + ProfileProperty property = new ProfileProperty("textures", string); + builder.addProperty(property); + profile = builder.build(); + } + } + + for (Entity entity : getExpr().getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + mannequin.setProfile(profile); + } + } + + @Override + public Class getReturnType() { + return Object.class; + } + + @Override + public Class[] possibleReturnTypes() { + return CollectionUtils.array(OfflinePlayer.class, String.class); + } + + @Override + protected String getPropertyName() { + return "mannequin skin"; + } + +} diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index e9853b2c01a..439daaba312 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -783,6 +783,14 @@ entities: 0: gray trader llama[plural:s] 1: baby:gray trader llama cria[plural:s] + # MannequinData + mannequin: + name: mannequin¦s + patterns: + 0: mannequin[plural:s] + 1: immovable mannequin[plural:s] + 2: movable mannequin[plural:s] + # MinecartData minecart: name: minecart¦s @@ -1593,9 +1601,6 @@ entities: copper golem: name: copper golem¦s pattern: copper golem[plural:s] - mannequin: - name: mannequin¦s - pattern: mannequin[plural:s] # SuperTypes human: diff --git a/src/test/skript/tests/misc/EntityData.sk b/src/test/skript/tests/misc/EntityData.sk index b1e02b2826e..1f4b14253b5 100644 --- a/src/test/skript/tests/misc/EntityData.sk +++ b/src/test/skript/tests/misc/EntityData.sk @@ -461,6 +461,11 @@ test "llama data": testData(baby gray trader llama) testData(gray trader llama cria) +test "mannequin data" when running minecraft "1.21.9": + setSuperTypes(mannequin) + testData(immovable mannequin) + testData(movable mannequin) + test "minecart data": setSuperTypes(minecart) testData(minecart) diff --git a/src/test/skript/tests/syntaxes/effects/EffMannequinImmovable.sk b/src/test/skript/tests/syntaxes/effects/EffMannequinImmovable.sk new file mode 100644 index 00000000000..9a22ae60294 --- /dev/null +++ b/src/test/skript/tests/syntaxes/effects/EffMannequinImmovable.sk @@ -0,0 +1,8 @@ +test "mannequin immovable" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + assert {_entity} is movable with "Mannequin should be movable on spawn" + make {_entity} immovable + assert {_entity} is immovable with "Mannequin should be immovable" + clear entity within {_entity} diff --git a/src/test/skript/tests/syntaxes/effects/EffMannequinParts.sk b/src/test/skript/tests/syntaxes/effects/EffMannequinParts.sk new file mode 100644 index 00000000000..8cdcde46c67 --- /dev/null +++ b/src/test/skript/tests/syntaxes/effects/EffMannequinParts.sk @@ -0,0 +1,77 @@ +test "mannequin parts" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + disable the mannequin cape for {_entity} + assert the mannequin cape of {_entity} is disabled with "Mannequin cape should be disabled" + enable the mannequin cape for {_entity} + assert the mannequin cape of {_entity} is enabled with "Mannequin cape should be enabled" + + disable the mannequin hat for {_entity} + assert the mannequin hat of {_entity} is disabled with "Mannequin hat should be disabled" + enable the mannequin hat for {_entity} + assert the mannequin hat of {_entity} is enabled with "Mannequin hat should be enabled" + + disable the mannequin jacket for {_entity} + assert the mannequin jacket of {_entity} is disabled with "Mannequin jacket should be disabled" + enable the mannequin jacket for {_entity} + assert the mannequin jacket of {_entity} is enabled with "Mannequin jacket should be enabled" + + disable the mannequin left pants for {_entity} + assert the mannequin left pants of {_entity} is disabled with "Mannequin left pants should be disabled" + enable the mannequin left pants for {_entity} + assert the mannequin left pants of {_entity} is enabled with "Mannequin left pants should be enabled" + + disable the mannequin left sleeve for {_entity} + assert the mannequin left sleeve of {_entity} is disabled with "Mannequin left sleeve should be disabled" + enable the mannequin left sleeve for {_entity} + assert the mannequin left sleeve of {_entity} is enabled with "Mannequin left sleeve should be enabled" + + disable the mannequin right pants for {_entity} + assert the mannequin right pants of {_entity} is disabled with "Mannequin right pants should be disabled" + enable the mannequin right pants for {_entity} + assert the mannequin right pants of {_entity} is enabled with "Mannequin right pants should be enabled" + + disable the mannequin right sleeve for {_entity} + assert the mannequin right sleeve of {_entity} is disabled with "Mannequin right sleeve should be disabled" + enable the mannequin right sleeve for {_entity} + assert the mannequin right sleeve of {_entity} is enabled with "Mannequin right sleeve should be enabled" + + disable the mannequin pants for {_entity} + assert the mannequin pants of {_entity} is disabled with "Mannequin pants should be disabled" + assert the mannequin left pants of {_entity} is disabled with "Mannequin left pants should be disabled after 'pants'" + assert the mannequin right pants of {_entity} is disabled with "Mannequin right pants should be disabled after 'pants'" + enable the mannequin pants for {_entity} + assert the mannequin pants of {_entity} is enabled with "Mannequin pants should be enabled" + assert the mannequin left pants of {_entity} is enabled with "Mannequin left pants should be enabled after 'pants'" + assert the mannequin right pants of {_entity} is enabled with "Mannequin right pants should be enabled after 'pants'" + + disable the mannequin sleeves for {_entity} + assert the mannequin sleeves of {_entity} is disabled with "Mannequin sleeves should be disabled" + assert the mannequin left sleeve of {_entity} is disabled with "Mannequin left sleeve should be disabled after 'sleeves'" + assert the mannequin right sleeve of {_entity} is disabled with "Mannequin right sleeve should be disabled after 'sleeves'" + enable the mannequin sleeves for {_entity} + assert the mannequin sleeves of {_entity} is enabled with "Mannequin sleeves should be enabled" + assert the mannequin left sleeve of {_entity} is enabled with "Mannequin left sleeve should be enabled after 'sleeves'" + assert the mannequin right sleeve of {_entity} is enabled with "Mannequin right sleeve should be enabled after 'sleeves'" + + disable all of the mannequin skin parts for {_entity} + assert all of the mannequin skin parts of {_entity} are disabled with "All mannequin skin parts should be disabled" + assert the mannequin cape of {_entity} is disabled with "Mannequin cape should be disabled after 'all'" + assert the mannequin hat of {_entity} is disabled with "Mannequin hat should be disabled after 'all'" + assert the mannequin jacket of {_entity} is disabled with "Mannequin jacket should be disabled after 'all'" + assert the mannequin left pants of {_entity} is disabled with "Mannequin left pants should be disabled after 'all'" + assert the mannequin left sleeve of {_entity} is disabled with "Mannequin left sleeve should be disabled after 'all'" + assert the mannequin right pants of {_entity} is disabled with "Mannequin right pants should be disabled after 'all'" + assert the mannequin right sleeve of {_entity} is disabled with "Mannequin right sleeve should be disabled after 'all'" + enable all of the mannequin skin parts for {_entity} + assert all of the mannequin skin parts of {_entity} are enabled with "All mannequin skin parts should be enabled" + assert the mannequin cape of {_entity} is enabled with "Mannequin cape should be enabled after 'all'" + assert the mannequin hat of {_entity} is enabled with "Mannequin hat should be enabled after 'all'" + assert the mannequin jacket of {_entity} is enabled with "Mannequin jacket should be enabled after 'all'" + assert the mannequin left pants of {_entity} is enabled with "Mannequin left pants should be enabled after 'all'" + assert the mannequin left sleeve of {_entity} is enabled with "Mannequin left sleeve should be enabled after 'all'" + assert the mannequin right pants of {_entity} is enabled with "Mannequin right pants should be enabled after 'all'" + assert the mannequin right sleeve of {_entity} is enabled with "Mannequin right sleeve should be enabled after 'all'" + + clear entity within {_entity} diff --git a/src/test/skript/tests/syntaxes/expressions/ExprMannequinDesc.sk b/src/test/skript/tests/syntaxes/expressions/ExprMannequinDesc.sk new file mode 100644 index 00000000000..668f491f197 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprMannequinDesc.sk @@ -0,0 +1,12 @@ +test "mannequin description" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + set the mannequin description of {_entity} to "SkriptLang" + assert the mannequin description of {_entity} is "SkriptLang" with "Mannequin description was not set" + clear the mannequin description of {_entity} + assert the mannequin description of {_entity} is not set with "Mannequin description was not cleared" + reset the mannequin description of {_entity} + assert the mannequin description of {_entity} is "NPC" with "Mannequin description was not reset" + + clear entity within {_entity} diff --git a/src/test/skript/tests/syntaxes/expressions/ExprMannequinSkin.sk b/src/test/skript/tests/syntaxes/expressions/ExprMannequinSkin.sk new file mode 100644 index 00000000000..ad7b6a3cd42 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprMannequinSkin.sk @@ -0,0 +1,13 @@ +options: + texture: "e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWJjNzNlN2VlNzA4ZTQ3NjU4YWY3YzMzMTZkY2VkNzk5NDUyNTg3NDg1NjM5ODA4ZDQ3OTVkMjNmYzY4NDU1MCJ9fX0=" + +test "mannequin skin" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + set the mannequin skin of {_entity} to test-offline-player + assert the mannequin skin of {_entity} is test-offline-player with "Mannequin skin was not set to test offline player" + set the mannequin skin of {_entity} to {@texture} + assert the mannequin skin of {_entity} is {@texture} with "Mannequin skin was not set to texture value" + + clear entity within {_entity} From 48c2e93e5f6601d925abd2b27a827e17b94248f2 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sat, 1 Nov 2025 22:15:36 -0400 Subject: [PATCH 2/6] Additional Commit --- .../skript/classes/data/BukkitClasses.java | 29 ++++- .../skript/conditions/CondIsLeftHanded.java | 35 +++--- .../ch/njol/skript/effects/EffHandedness.java | 31 +++-- .../bukkit/mannequin/MannequinModule.java | 31 +++-- .../mannequin/ResolvableProfileBuilder.java | 69 +++++++++++ .../bukkit/mannequin/SkinPatchBuilder.java | 55 +++++++++ .../mannequin/elements/ExprMannequinBody.java | 115 ++++++++++++++++++ .../mannequin/elements/ExprMannequinCape.java | 115 ++++++++++++++++++ .../elements/ExprMannequinElytra.java | 115 ++++++++++++++++++ .../elements/ExprMannequinModel.java | 93 ++++++++++++++ src/main/resources/lang/default.lang | 6 + .../tests/syntaxes/effects/EffHandedness.sk | 9 ++ .../syntaxes/expressions/ExprMannequinBody.sk | 12 ++ .../syntaxes/expressions/ExprMannequinCape.sk | 12 ++ .../expressions/ExprMannequinElytra.sk | 12 ++ .../expressions/ExprMannequinModel.sk | 10 ++ 16 files changed, 703 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprMannequinBody.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprMannequinCape.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprMannequinElytra.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprMannequinModel.sk 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 9794bfc2e22..a9e95480242 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -4,7 +4,11 @@ import ch.njol.skript.bukkitutil.BukkitUtils; import ch.njol.skript.bukkitutil.EntityUtils; import ch.njol.skript.bukkitutil.SkriptTeleportFlag; -import ch.njol.skript.classes.*; +import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.EnumClassInfo; +import ch.njol.skript.classes.Parser; +import ch.njol.skript.classes.PatternedParser; +import ch.njol.skript.classes.Serializer; import ch.njol.skript.classes.registry.RegistryClassInfo; import ch.njol.skript.expressions.ExprDamageCause; import ch.njol.skript.expressions.base.EventValueExpression; @@ -26,7 +30,12 @@ import org.bukkit.command.CommandSender; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentOffer; -import org.bukkit.entity.*; +import org.bukkit.entity.EntitySnapshot; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Vehicle; +import org.bukkit.entity.Villager; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityPotionEffectEvent; @@ -49,11 +58,18 @@ import org.bukkit.metadata.Metadatable; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; +import org.bukkit.profile.PlayerTextures.SkinModel; import org.bukkit.util.CachedServerIcon; import org.bukkit.util.Vector; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.base.types.*; +import org.skriptlang.skript.bukkit.base.types.BlockClassInfo; +import org.skriptlang.skript.bukkit.base.types.EntityClassInfo; import org.skriptlang.skript.bukkit.base.types.EntityClassInfo.EntityChanger; +import org.skriptlang.skript.bukkit.base.types.InventoryClassInfo; +import org.skriptlang.skript.bukkit.base.types.ItemStackClassInfo; +import org.skriptlang.skript.bukkit.base.types.NameableClassInfo; +import org.skriptlang.skript.bukkit.base.types.OfflinePlayerClassInfo; +import org.skriptlang.skript.bukkit.base.types.PlayerClassInfo; import org.skriptlang.skript.lang.properties.Property; import org.skriptlang.skript.lang.properties.PropertyHandler.ExpressionPropertyHandler; @@ -1140,5 +1156,12 @@ public String toVariableNameString(WorldBorder border) { .since("2.12") ); + Classes.registerClass(new EnumClassInfo<>(SkinModel.class, "skinmodel", "skin models") + .user("skin ?models?") + .name("Skin Model") + .description("Represents a skin model.") + .since("INSERT VERSION") + ); + } } diff --git a/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java b/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java index e7fc5ed1c98..9a67358fb78 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsLeftHanded.java @@ -3,38 +3,34 @@ import ch.njol.skript.Skript; import ch.njol.skript.conditions.base.PropertyCondition; import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Example; import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Mob; import org.bukkit.inventory.MainHand; @Name("Left Handed") -@Description({ - "Checks if living entities or players are left or right-handed. Armor stands are neither right nor left-handed." -}) -@Examples({ - "on damage of player:", - "\tif victim is left handed:", - "\t\tcancel event" -}) -@Since("2.8.0") +@Description("Checks if living entities or players are left or right-handed. Armor stands are neither right nor left-handed.") +@Example(""" + on damage of player: + if victim is left handed: + cancel event + """) +@RequiredPlugins("Minecraft 1.21.9+ (mannequins)") +@Since("2.8.0, INSERT VERSION (mannequins)") public class CondIsLeftHanded extends PropertyCondition { - // TODO - remove this when Spigot support is dropped - private static final boolean CAN_USE_ENTITIES = Skript.methodExists(Mob.class, "isLeftHanded"); + private static final boolean MANNEQUIN_EXISTS = Skript.classExists("org.bukkit.entity.Mannequin"); static { - if (CAN_USE_ENTITIES) { - register(CondIsLeftHanded.class, "(:left|right)( |-)handed", "livingentities"); - } else { - register(CondIsLeftHanded.class, "(:left|right)( |-)handed", "players"); - } + register(CondIsLeftHanded.class, "(:left|right)( |-)handed", "entities"); } private MainHand hand; @@ -48,13 +44,16 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, @Override public boolean check(LivingEntity livingEntity) { // check if entity is a mob and if the method exists - if (CAN_USE_ENTITIES && livingEntity instanceof Mob mob) + if (livingEntity instanceof Mob mob) return mob.isLeftHanded() == (hand == MainHand.LEFT); // check if entity is a player if (livingEntity instanceof HumanEntity humanEntity) return humanEntity.getMainHand() == hand; + if (MANNEQUIN_EXISTS && livingEntity instanceof Mannequin mannequin) + return mannequin.getMainHand() == hand; + // invalid entity return false; } diff --git a/src/main/java/ch/njol/skript/effects/EffHandedness.java b/src/main/java/ch/njol/skript/effects/EffHandedness.java index d7f29122d3e..0edc701e3c0 100644 --- a/src/main/java/ch/njol/skript/effects/EffHandedness.java +++ b/src/main/java/ch/njol/skript/effects/EffHandedness.java @@ -2,32 +2,36 @@ import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Example; import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Mob; import org.bukkit.event.Event; +import org.bukkit.inventory.MainHand; import org.jetbrains.annotations.Nullable; @Name("Handedness") @Description("Make mobs left or right-handed. This does not affect players.") -@Examples({ - "spawn skeleton at spawn of world \"world\":", - "\tmake entity left handed", - "", - "make all zombies in radius 10 of player right handed" -}) -@Since("2.8.0") +@Example(""" + spawn skeleton at spawn of world "world": + make entity left handed + """) +@Example("make all zombies in radius 10 of player right handed") +@RequiredPlugins("Minecraft 1.21.9+ (mannequins)") +@Since("2.8.0, INSERT VERSION (mannequins)") public class EffHandedness extends Effect { + private static final boolean MANNEQUIN_EXISTS = Skript.classExists("org.bukkit.entity.Mannequin"); + static { - if (Skript.methodExists(Mob.class, "setLeftHanded", boolean.class)) - Skript.registerEffect(EffHandedness.class, "make %livingentities% (:left|right)( |-)handed"); + Skript.registerEffect(EffHandedness.class, "make %livingentities% (:left|right)( |-)handed"); } private boolean leftHanded; @@ -42,9 +46,12 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @Override protected void execute(Event event) { + MainHand mainHand = leftHanded ? MainHand.LEFT : MainHand.RIGHT; for (LivingEntity livingEntity : livingEntities.getArray(event)) { - if (livingEntity instanceof Mob) { - ((Mob) livingEntity).setLeftHanded(leftHanded); + if (livingEntity instanceof Mob mob) { + mob.setLeftHanded(leftHanded); + } else if (MANNEQUIN_EXISTS && livingEntity instanceof Mannequin mannequin) { + mannequin.setMainHand(mainHand); } } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java index 773e495b1b1..5c7410c7f8d 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java @@ -3,14 +3,12 @@ import ch.njol.skript.Skript; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.SkriptAddon; -import org.skriptlang.skript.bukkit.mannequin.elements.CondMannequinImmovable; -import org.skriptlang.skript.bukkit.mannequin.elements.CondMannequinParts; -import org.skriptlang.skript.bukkit.mannequin.elements.EffMannequinImmovable; -import org.skriptlang.skript.bukkit.mannequin.elements.EffMannequinParts; -import org.skriptlang.skript.bukkit.mannequin.elements.ExprMannequinDesc; -import org.skriptlang.skript.bukkit.mannequin.elements.ExprMannequinSkin; +import org.skriptlang.skript.bukkit.mannequin.elements.*; import org.skriptlang.skript.registration.SyntaxRegistry; +import java.util.Set; +import java.util.function.Consumer; + public class MannequinModule implements AddonModule { @Override @@ -20,14 +18,21 @@ public boolean canLoad(SkriptAddon addon) { @Override public void load(SkriptAddon addon) { - SyntaxRegistry registry = addon.syntaxRegistry(); + Set> elementsToLoad = Set.of( + CondMannequinImmovable::register, + CondMannequinParts::register, + EffMannequinImmovable::register, + EffMannequinParts::register, + ExprMannequinBody::register, + ExprMannequinCape::register, + ExprMannequinDesc::register, + ExprMannequinElytra::register, + ExprMannequinModel::register, + ExprMannequinSkin::register + ); - CondMannequinParts.register(registry); - CondMannequinImmovable.register(registry); - EffMannequinParts.register(registry); - EffMannequinImmovable.register(registry); - ExprMannequinDesc.register(registry); - ExprMannequinSkin.register(registry); + SyntaxRegistry registry = addon.syntaxRegistry(); + elementsToLoad.forEach(element -> element.accept(registry)); MannequinData.register(); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java new file mode 100644 index 00000000000..15b1298ec0c --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java @@ -0,0 +1,69 @@ +package org.skriptlang.skript.bukkit.mannequin; + +import com.destroystokyo.paper.profile.ProfileProperty; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +/** + * Helper class for taking a finalized {@link ResolvableProfile} and turning it into a builder. + */ +@SuppressWarnings("UnstableApiUsage") +public class ResolvableProfileBuilder { + + private Collection properties = new ArrayList<>(); + private @Nullable String name = null; + private SkinPatch skinPatch = SkinPatch.empty(); + private @Nullable UUID uuid = null; + + public ResolvableProfileBuilder(ResolvableProfile profile) { + properties = profile.properties(); + name = profile.name(); + skinPatch = profile.skinPatch(); + uuid = profile.uuid(); + } + + public ResolvableProfileBuilder addProperties(Collection properties) { + this.properties.addAll(properties); + return this; + } + + public ResolvableProfileBuilder addProperty(ProfileProperty property) { + this.properties.add(property); + return this; + } + + public ResolvableProfileBuilder setProperties(Collection properties) { + this.properties = properties; + return this; + } + + public ResolvableProfileBuilder name(@Nullable String name) { + this.name = name; + return this; + } + + public ResolvableProfileBuilder skinPatch(SkinPatch skinPatch) { + this.skinPatch = skinPatch; + return this; + } + + public ResolvableProfileBuilder uuid(@Nullable UUID uuid) { + this.uuid = uuid; + return this; + } + + public ResolvableProfile build() { + return ResolvableProfile.resolvableProfile() + .addProperties(properties) + .name(name) + .skinPatch(skinPatch) + .uuid(uuid) + .build(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java new file mode 100644 index 00000000000..c3a8fc86dab --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java @@ -0,0 +1,55 @@ +package org.skriptlang.skript.bukkit.mannequin; + +import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; +import net.kyori.adventure.key.Key; +import org.bukkit.profile.PlayerTextures.SkinModel; +import org.jetbrains.annotations.Nullable; + +/** + * Helper class for taking a finalized {@link SkinPatch} and turning it into a builder. + */ +@SuppressWarnings("UnstableApiUsage") +public class SkinPatchBuilder { + + private @Nullable Key body = null; + private @Nullable Key cape = null; + private @Nullable Key elytra = null; + private @Nullable SkinModel model = null; + + public SkinPatchBuilder(SkinPatch skinPatch) { + body = skinPatch.body(); + cape = skinPatch.cape(); + elytra = skinPatch.elytra(); + model = skinPatch.model(); + } + + public SkinPatchBuilder body(@Nullable Key body) { + this.body = body; + return this; + } + + public SkinPatchBuilder cape(@Nullable Key cape) { + this.cape = cape; + return this; + } + + public SkinPatchBuilder elytra(@Nullable Key elytra) { + this.elytra = elytra; + return this; + } + + public SkinPatchBuilder model(@Nullable SkinModel model) { + this.model = model; + return this; + } + + public SkinPatch build() { + return SkinPatch.skinPatch() + .body(body) + .cape(cape) + .elytra(elytra) + .model(model) + .build(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java new file mode 100644 index 00000000000..07bbd4a297b --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java @@ -0,0 +1,115 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.bukkitutil.NamespacedUtils; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ValidationResult; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Mannequin Body") +@Description(""" + The body texture displayed on a mannequin. + The body key is represented as a namespaced key. + A namespaced key can be formatted as 'namespace:id' or 'id'. \ + It can only contain one ':' to separate the namespace and the id. \ + Only alphanumeric characters, periods, underscores, and dashes can be used. + """) +@Example("set the mannequin body of {_mannequin} to \"custom:body\"") +@Example("clear the mannequin body key of last spawned mannequin") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class ExprMannequinBody extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprMannequinBody.class, + String.class, + "mannequin body [texture] [key]", + "entities", + false + ).supplier(ExprMannequinBody::new) + .build() + ); + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public @Nullable String convert(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return null; + SkinPatch skinPatch = mannequin.getProfile().skinPatch(); + Key key = skinPatch.body(); + return key == null ? null : key.asString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Key key = null; + if (delta != null) { + String string = (String) delta[0]; + ValidationResult result = NamespacedUtils.checkValidation(string); + String message = result.message(); + if (!result.valid()) { + error(message + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + return; + } else if (message != null) { + warning(message); + } + key = result.data(); + } + + for (Entity entity : getExpr().getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + ResolvableProfile profile = mannequin.getProfile(); + SkinPatch skinPatch = profile.skinPatch(); + if (skinPatch.body() == key) + continue; + SkinPatch newPatch = new SkinPatchBuilder(skinPatch) + .body(key) + .build(); + ResolvableProfile newProfile = new ResolvableProfileBuilder(profile) + .skinPatch(newPatch) + .build(); + newProfile.resolve(); + mannequin.setProfile(newProfile); + } + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "mannequin body"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java new file mode 100644 index 00000000000..bf2a92364bf --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java @@ -0,0 +1,115 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.bukkitutil.NamespacedUtils; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ValidationResult; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Mannequin Cape") +@Description(""" + The cape texture displayed on a mannequin. + The cape key is represented as a namespaced key. + A namespaced key can be formatted as 'namespace:id' or 'id'. \ + It can only contain one ':' to separate the namespace and the id. \ + Only alphanumeric characters, periods, underscores, and dashes can be used. + """) +@Example("set the mannequin cape of {_mannequin} to \"custom:cape\"") +@Example("clear the mannequin cape key of last spawned mannequin") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class ExprMannequinCape extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprMannequinCape.class, + String.class, + "mannequin cape [texture] [key]", + "entities", + false + ).supplier(ExprMannequinCape::new) + .build() + ); + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public @Nullable String convert(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return null; + SkinPatch skinPatch = mannequin.getProfile().skinPatch(); + Key key = skinPatch.cape(); + return key == null ? null : key.asString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Key key = null; + if (delta != null) { + String string = (String) delta[0]; + ValidationResult result = NamespacedUtils.checkValidation(string); + String message = result.message(); + if (!result.valid()) { + error(message + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + return; + } else if (message != null) { + warning(message); + } + key = result.data(); + } + + for (Entity entity : getExpr().getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + ResolvableProfile profile = mannequin.getProfile(); + SkinPatch skinPatch = profile.skinPatch(); + if (skinPatch.cape() == key) + continue; + SkinPatch newPatch = new SkinPatchBuilder(skinPatch) + .cape(key) + .build(); + ResolvableProfile newProfile = new ResolvableProfileBuilder(profile) + .skinPatch(newPatch) + .build(); + newProfile.resolve(); + mannequin.setProfile(newProfile); + } + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "mannequin cape"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java new file mode 100644 index 00000000000..642b7e44e7b --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java @@ -0,0 +1,115 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.bukkitutil.NamespacedUtils; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ValidationResult; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Mannequin Elytra") +@Description(""" + The elytra texture displayed on a mannequin. + The elytra key is represented as a namespaced key. + A namespaced key can be formatted as 'namespace:id' or 'id'. \ + It can only contain one ':' to separate the namespace and the id. \ + Only alphanumeric characters, periods, underscores, and dashes can be used. + """) +@Example("set the mannequin elytra of {_mannequin} to \"custom:elytra\"") +@Example("clear the mannequin elytra key of last spawned mannequin") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class ExprMannequinElytra extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprMannequinElytra.class, + String.class, + "mannequin elytra [texture] [key]", + "entities", + false + ).supplier(ExprMannequinElytra::new) + .build() + ); + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public @Nullable String convert(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return null; + SkinPatch skinPatch = mannequin.getProfile().skinPatch(); + Key key = skinPatch.elytra(); + return key == null ? null : key.asString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Key key = null; + if (delta != null) { + String string = (String) delta[0]; + ValidationResult result = NamespacedUtils.checkValidation(string); + String message = result.message(); + if (!result.valid()) { + error(message + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + return; + } else if (message != null) { + warning(message); + } + key = result.data(); + } + + for (Entity entity : getExpr().getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + ResolvableProfile profile = mannequin.getProfile(); + SkinPatch skinPatch = profile.skinPatch(); + if (skinPatch.elytra() == key) + continue; + SkinPatch newPatch = new SkinPatchBuilder(skinPatch) + .elytra(key) + .build(); + ResolvableProfile newProfile = new ResolvableProfileBuilder(profile) + .skinPatch(newPatch) + .build(); + newProfile.resolve(); + mannequin.setProfile(newProfile); + } + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "mannequin elytra"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java new file mode 100644 index 00000000000..f4af055bb8c --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java @@ -0,0 +1,93 @@ +package org.skriptlang.skript.bukkit.mannequin.elements; + +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Example; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.event.Event; +import org.bukkit.profile.PlayerTextures.SkinModel; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.registration.SyntaxRegistry; + +@Name("Mannequin Model") +@Description("The skin model of a mannequin.") +@Example("set the mannequin model to classic") +@Example("set the mannequin skin model to slim") +@RequiredPlugins("Minecraft 1.21.9+") +@Since("INSERT VERSION") +public class ExprMannequinModel extends SimplePropertyExpression { + + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder( + ExprMannequinModel.class, + SkinModel.class, + "mannequin [skin] model", + "entities", + false + ).supplier(ExprMannequinModel::new) + .build() + ); + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public @Nullable SkinModel convert(Entity entity) { + if (!(entity instanceof Mannequin mannequin)) + return null; + SkinPatch skinPatch = mannequin.getProfile().skinPatch(); + return skinPatch.model(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(SkinModel.class); + return null; + } + + @Override + @SuppressWarnings("UnstableApiUsage") + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + SkinModel model = delta == null ? null : (SkinModel) delta[0]; + + for (Entity entity : getExpr().getArray(event)) { + if (!(entity instanceof Mannequin mannequin)) + continue; + ResolvableProfile profile = mannequin.getProfile(); + SkinPatch skinPatch = profile.skinPatch(); + if (skinPatch.model() == model) + continue; + SkinPatch newPatch = new SkinPatchBuilder(skinPatch) + .model(model) + .build(); + ResolvableProfile newProfile = new ResolvableProfileBuilder(profile) + .skinPatch(newPatch) + .build(); + newProfile.resolve(); + mannequin.setProfile(newProfile); + } + } + + @Override + public Class getReturnType() { + return SkinModel.class; + } + + @Override + protected String getPropertyName() { + return "mannequin model"; + } + +} diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index 439daaba312..6035dfa9a89 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -3018,6 +3018,11 @@ damage types: wither: wither wither_skull: wither skull +# -- Skin Models -- +skin models: + classic: classic, classic skin, classic skin model, classic model + slim: slim, slim skin, slim skin model, slim model + # -- Boolean -- boolean: true: @@ -3138,6 +3143,7 @@ types: frogvariant: frog variant¦s @a itemcomponent: item component¦s @an equippablecomponent: equippable component¦s @an + skinmodel: skin model¦s @a # Skript weathertype: weather type¦s @a diff --git a/src/test/skript/tests/syntaxes/effects/EffHandedness.sk b/src/test/skript/tests/syntaxes/effects/EffHandedness.sk index 7d55bc1abda..1498f5b67be 100644 --- a/src/test/skript/tests/syntaxes/effects/EffHandedness.sk +++ b/src/test/skript/tests/syntaxes/effects/EffHandedness.sk @@ -9,3 +9,12 @@ test "left handedness": make entity left handed assert entity is left handed with "zombie is not left handed after being made left handed again" delete entity + +test "mannequin handedness" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + make {_entity} right handed + assert {_entity} is right handed with "Mannequin should be right handed" + make {_entity} left handed + assert {_entity} is left handed with "Mannequin should be left handed" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprMannequinBody.sk b/src/test/skript/tests/syntaxes/expressions/ExprMannequinBody.sk new file mode 100644 index 00000000000..ba00c7ad4e4 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprMannequinBody.sk @@ -0,0 +1,12 @@ +test "mannequin body" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + loop "custom:body1", "custom:body2" and "custom:body3": + set the mannequin body of {_entity} to loop-value + assert the mannequin body of {_entity} is loop-value with "Mannequin body should be '%loop-value%'" + + clear the mannequin body of {_entity} + assert the mannequin body of {_entity} is not set with "Mannequin body was not cleared" + + clear entity within {_entity} diff --git a/src/test/skript/tests/syntaxes/expressions/ExprMannequinCape.sk b/src/test/skript/tests/syntaxes/expressions/ExprMannequinCape.sk new file mode 100644 index 00000000000..7f4033303a8 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprMannequinCape.sk @@ -0,0 +1,12 @@ +test "mannequin cape" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + loop "custom:cape1", "custom:cape2" and "custom:cape3": + set the mannequin cape of {_entity} to loop-value + assert the mannequin cape of {_entity} is loop-value with "Mannequin cape should be '%loop-value%'" + + clear the mannequin cape of {_entity} + assert the mannequin cape of {_entity} is not set with "Mannequin cape was not cleared" + + clear entity within {_entity} diff --git a/src/test/skript/tests/syntaxes/expressions/ExprMannequinElytra.sk b/src/test/skript/tests/syntaxes/expressions/ExprMannequinElytra.sk new file mode 100644 index 00000000000..9ad9aa5a1c6 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprMannequinElytra.sk @@ -0,0 +1,12 @@ +test "mannequin elytra" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + loop "custom:elytra1", "custom:elytra2" and "custom:elytra3": + set the mannequin elytra of {_entity} to loop-value + assert the mannequin elytra of {_entity} is loop-value with "Mannequin elytra should be '%loop-value%'" + + clear the mannequin elytra of {_entity} + assert the mannequin elytra of {_entity} is not set with "Mannequin elytra was not cleared" + + clear entity within {_entity} diff --git a/src/test/skript/tests/syntaxes/expressions/ExprMannequinModel.sk b/src/test/skript/tests/syntaxes/expressions/ExprMannequinModel.sk new file mode 100644 index 00000000000..a82ecac476f --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprMannequinModel.sk @@ -0,0 +1,10 @@ +test "mannequin elytra" when running minecraft "1.21.9": + spawn a mannequin at test-location: + set {_entity} to entity + + set the mannequin model of {_entity} to classic + assert the mannequin model of {_entity} is classic with "Mannequin model should be classic" + set the mannequin model of {_entity} to slim + assert the mannequin model of {_entity} is slim with "Mannequin model should be slim" + + clear entity within {_entity} From 917dfb8c4f4bcf26b7bc15a7cdeaf10ed4477d20 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sun, 2 Nov 2025 17:55:45 -0500 Subject: [PATCH 3/6] Efy's Changes --- .../njol/skript/entity/SimpleEntityData.java | 1 - .../mannequin/ResolvableProfileBuilder.java | 33 +++++++++++++++++++ .../bukkit/mannequin/SkinPatchBuilder.java | 23 +++++++++++++ .../elements/EffMannequinImmovable.java | 4 +-- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/njol/skript/entity/SimpleEntityData.java b/src/main/java/ch/njol/skript/entity/SimpleEntityData.java index d723321dca0..3e47b3ab58a 100644 --- a/src/main/java/ch/njol/skript/entity/SimpleEntityData.java +++ b/src/main/java/ch/njol/skript/entity/SimpleEntityData.java @@ -242,7 +242,6 @@ private static void addSuperEntity(String codeName, Class enti if (Skript.isRunningMinecraft(1, 21, 9)) { addSimpleEntity("copper golem", CopperGolem.class); - addSimpleEntity("mannequin", Mannequin.class); } // SuperTypes diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java index 15b1298ec0c..939bf2474f4 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java @@ -27,36 +27,69 @@ public ResolvableProfileBuilder(ResolvableProfile profile) { uuid = profile.uuid(); } + /** + * Add {@link ProfileProperty}s to be used in the final {@link ResolvableProfile}. + * @param properties The {@link ProfileProperty}s to add. + * @return {@code this} + */ public ResolvableProfileBuilder addProperties(Collection properties) { this.properties.addAll(properties); return this; } + /** + * Add a {@link ProfileProperty} to be used in the final {@link ResolvableProfile}. + * @param property The {@link ProfileProperty} to add. + * @return {@code this} + */ public ResolvableProfileBuilder addProperty(ProfileProperty property) { this.properties.add(property); return this; } + /** + * Sets the {@link ProfileProperty}s to be used in the final {@link ResolvableProfile}. + * @param properties The {@link ProfileProperty}s to set. + * @return {@code this} + */ public ResolvableProfileBuilder setProperties(Collection properties) { this.properties = properties; return this; } + /** + * The name to be used in the final {@link ResolvableProfile}. + * @param name The name. + * @return {@code this} + */ public ResolvableProfileBuilder name(@Nullable String name) { this.name = name; return this; } + /** + * The {@link SkinPatch} to be used in the final {@link ResolvableProfile}. + * @param skinPatch The {@link SkinPatch}. + * @return {@code this} + */ public ResolvableProfileBuilder skinPatch(SkinPatch skinPatch) { this.skinPatch = skinPatch; return this; } + /** + * The {@link UUID} to be used in the final {@link ResolvableProfile}. + * @param uuid The {@link UUID}. + * @return {@code this} + */ public ResolvableProfileBuilder uuid(@Nullable UUID uuid) { this.uuid = uuid; return this; } + /** + * @return The finalized {@link ResolvableProfile}. + */ public ResolvableProfile build() { return ResolvableProfile.resolvableProfile() .addProperties(properties) diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java index c3a8fc86dab..d6accd5536f 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java @@ -23,26 +23,49 @@ public SkinPatchBuilder(SkinPatch skinPatch) { model = skinPatch.model(); } + /** + * The body texture to be used in the final {@link SkinPatch}. + * @param body The body texture. + * @return {@code this} + */ public SkinPatchBuilder body(@Nullable Key body) { this.body = body; return this; } + /** + * The cape texture to be used in the final {@link SkinPatch}. + * @param cape The cape texture. + * @return {@code this} + */ public SkinPatchBuilder cape(@Nullable Key cape) { this.cape = cape; return this; } + /** + * The elytra texture to be used in the final {@link SkinPatch}. + * @param elytra The elytra texture. + * @return {@code this} + */ public SkinPatchBuilder elytra(@Nullable Key elytra) { this.elytra = elytra; return this; } + /** + * The {@link SkinModel} to be used in the final {@link SkinPatch}. + * @param model The {@link SkinModel}. + * @return {@code this} + */ public SkinPatchBuilder model(@Nullable SkinModel model) { this.model = model; return this; } + /** + * @return The finalized {@link SkinPatch}. + */ public SkinPatch build() { return SkinPatch.skinPatch() .body(body) diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java index 118368d6786..b46e8e3e77b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java @@ -59,9 +59,9 @@ protected void execute(Event event) { @Override public String toString(@Nullable Event event, boolean debug) { - String move = immovable ? "immovable" : "movable"; return new SyntaxStringBuilder(event, debug) - .append("make", entities, move) + .append("make", entities) + .append(immovable ? "immovable" : "movable") .toString(); } From f74b29019ec6692691cebb11573c903f5346349a Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sun, 2 Nov 2025 17:59:38 -0500 Subject: [PATCH 4/6] Update CondMannequinParts.java --- .../bukkit/mannequin/elements/CondMannequinParts.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java index 92539f638b5..aee4f22a9e6 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java +++ b/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java @@ -24,7 +24,14 @@ @Name("Mannequin Skin Part is Enabled") @Description("Whether a specific skin part of a mannequin is enabled or disabled.") -@Example("") +@Example(""" + if the mannequin cape of {_mannequin} is disabled: + enable the mannequin cape of {_mannequin} + """) +@Example(""" + if all of the mannequin skin parts of last spawned mannequin is revealed: + hide all of the mannequin skin parts for last spawned mannequin + """) @RequiredPlugins("Minecraft 1.21.9+") @Since("INSERT VERSION") public class CondMannequinParts extends Condition { From c510f3f3378d105d780e94fa638d4c3623299c56 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Mon, 3 Nov 2025 10:07:40 -0500 Subject: [PATCH 5/6] Entity Package/Module --- src/main/java/ch/njol/skript/Skript.java | 4 ++-- .../skript/bukkit/entity/EntityModule.java | 14 ++++++++++++++ .../{ => entity}/mannequin/MannequinData.java | 2 +- .../{ => entity}/mannequin/MannequinModule.java | 4 ++-- .../mannequin/ResolvableProfileBuilder.java | 2 +- .../{ => entity}/mannequin/SkinPatchBuilder.java | 2 +- .../mannequin/elements/CondMannequinImmovable.java | 2 +- .../mannequin/elements/CondMannequinParts.java | 4 ++-- .../mannequin/elements/EffMannequinImmovable.java | 2 +- .../mannequin/elements/EffMannequinParts.java | 2 +- .../mannequin/elements/ExprMannequinBody.java | 6 +++--- .../mannequin/elements/ExprMannequinCape.java | 6 +++--- .../mannequin/elements/ExprMannequinDesc.java | 2 +- .../mannequin/elements/ExprMannequinElytra.java | 6 +++--- .../mannequin/elements/ExprMannequinModel.java | 6 +++--- .../mannequin/elements/ExprMannequinSkin.java | 2 +- 16 files changed, 40 insertions(+), 26 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/MannequinData.java (97%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/MannequinModule.java (89%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/ResolvableProfileBuilder.java (98%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/SkinPatchBuilder.java (97%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/CondMannequinImmovable.java (96%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/CondMannequinParts.java (96%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/EffMannequinImmovable.java (96%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/EffMannequinParts.java (98%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/ExprMannequinBody.java (94%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/ExprMannequinCape.java (94%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/ExprMannequinDesc.java (97%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/ExprMannequinElytra.java (94%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/ExprMannequinModel.java (92%) rename src/main/java/org/skriptlang/skript/bukkit/{ => entity}/mannequin/elements/ExprMannequinSkin.java (98%) diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 5af27e9bfd9..58155091822 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -95,13 +95,13 @@ import org.skriptlang.skript.bukkit.brewing.BrewingModule; import org.skriptlang.skript.bukkit.damagesource.DamageSourceModule; import org.skriptlang.skript.bukkit.displays.DisplayModule; +import org.skriptlang.skript.bukkit.entity.EntityModule; import org.skriptlang.skript.bukkit.fishing.FishingModule; import org.skriptlang.skript.bukkit.furnace.FurnaceModule; import org.skriptlang.skript.bukkit.input.InputModule; import org.skriptlang.skript.bukkit.itemcomponents.ItemComponentModule; import org.skriptlang.skript.bukkit.log.runtime.BukkitRuntimeErrorConsumer; import org.skriptlang.skript.bukkit.loottables.LootTableModule; -import org.skriptlang.skript.bukkit.mannequin.MannequinModule; import org.skriptlang.skript.bukkit.registration.BukkitRegistryKeys; import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos; import org.skriptlang.skript.bukkit.tags.TagModule; @@ -601,7 +601,7 @@ public void onEnable() { new ItemComponentModule(), new BrewingModule(), new CommonModule(), - new MannequinModule() + new EntityModule() ); } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java b/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java new file mode 100644 index 00000000000..0332265bd43 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/EntityModule.java @@ -0,0 +1,14 @@ +package org.skriptlang.skript.bukkit.entity; + +import org.skriptlang.skript.addon.AddonModule; +import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.bukkit.entity.mannequin.MannequinModule; + +public class EntityModule implements AddonModule { + + @Override + public void load(SkriptAddon addon) { + addon.loadModules(new MannequinModule()); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/MannequinData.java similarity index 97% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/MannequinData.java index 2843f95af55..707ea5a0fed 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinData.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/MannequinData.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin; +package org.skriptlang.skript.bukkit.entity.mannequin; import ch.njol.skript.entity.EntityData; import ch.njol.skript.lang.Literal; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/MannequinModule.java similarity index 89% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/MannequinModule.java index 5c7410c7f8d..117f406faac 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/MannequinModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/MannequinModule.java @@ -1,9 +1,9 @@ -package org.skriptlang.skript.bukkit.mannequin; +package org.skriptlang.skript.bukkit.entity.mannequin; import ch.njol.skript.Skript; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.SkriptAddon; -import org.skriptlang.skript.bukkit.mannequin.elements.*; +import org.skriptlang.skript.bukkit.entity.mannequin.elements.*; import org.skriptlang.skript.registration.SyntaxRegistry; import java.util.Set; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/ResolvableProfileBuilder.java similarity index 98% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/ResolvableProfileBuilder.java index 939bf2474f4..a22cbd673ef 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/ResolvableProfileBuilder.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/ResolvableProfileBuilder.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin; +package org.skriptlang.skript.bukkit.entity.mannequin; import com.destroystokyo.paper.profile.ProfileProperty; import io.papermc.paper.datacomponent.item.ResolvableProfile; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/SkinPatchBuilder.java similarity index 97% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/SkinPatchBuilder.java index d6accd5536f..0a18fceb944 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/SkinPatchBuilder.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/SkinPatchBuilder.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin; +package org.skriptlang.skript.bukkit.entity.mannequin; import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; import net.kyori.adventure.key.Key; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/CondMannequinImmovable.java similarity index 96% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/CondMannequinImmovable.java index 2cd32915808..636179685a1 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinImmovable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/CondMannequinImmovable.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.conditions.base.PropertyCondition; import ch.njol.skript.doc.Description; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/CondMannequinParts.java similarity index 96% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/CondMannequinParts.java index aee4f22a9e6..c333bf3f904 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/CondMannequinParts.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/CondMannequinParts.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Example; @@ -16,7 +16,7 @@ import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.mannequin.elements.EffMannequinParts.MannequinPart; +import org.skriptlang.skript.bukkit.entity.mannequin.elements.EffMannequinParts.MannequinPart; import org.skriptlang.skript.registration.SyntaxInfo; import org.skriptlang.skript.registration.SyntaxRegistry; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinImmovable.java similarity index 96% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinImmovable.java index b46e8e3e77b..f0a908b034f 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinImmovable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinImmovable.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Example; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java similarity index 98% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java index 878c5e267ee..c3daec04d71 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/EffMannequinParts.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Example; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java similarity index 94% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java index 07bbd4a297b..4cd5da84494 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinBody.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.bukkitutil.NamespacedUtils; import ch.njol.skript.classes.Changer.ChangeMode; @@ -18,8 +18,8 @@ import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; -import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.SkinPatchBuilder; import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Mannequin Body") diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java similarity index 94% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java index bf2a92364bf..cb1945a50c1 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinCape.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.bukkitutil.NamespacedUtils; import ch.njol.skript.classes.Changer.ChangeMode; @@ -18,8 +18,8 @@ import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; -import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.SkinPatchBuilder; import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Mannequin Cape") diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinDesc.java similarity index 97% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinDesc.java index 2465c45720f..a31e284d790 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinDesc.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinDesc.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java similarity index 94% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java index 642b7e44e7b..1daa32a10d2 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinElytra.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.bukkitutil.NamespacedUtils; import ch.njol.skript.classes.Changer.ChangeMode; @@ -18,8 +18,8 @@ import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; -import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.SkinPatchBuilder; import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Mannequin Elytra") diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinModel.java similarity index 92% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinModel.java index f4af055bb8c..84f99b6518f 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinModel.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinModel.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; @@ -15,8 +15,8 @@ import org.bukkit.event.Event; import org.bukkit.profile.PlayerTextures.SkinModel; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.mannequin.ResolvableProfileBuilder; -import org.skriptlang.skript.bukkit.mannequin.SkinPatchBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.ResolvableProfileBuilder; +import org.skriptlang.skript.bukkit.entity.mannequin.SkinPatchBuilder; import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Mannequin Model") diff --git a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java similarity index 98% rename from src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java rename to src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java index fe9db7be341..858c25b7bc8 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/mannequin/elements/ExprMannequinSkin.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.mannequin.elements; +package org.skriptlang.skript.bukkit.entity.mannequin.elements; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; From 7d1f2276797bde77ba79c1f56bf0102c5fed40d0 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Fri, 7 Nov 2025 23:08:12 -0500 Subject: [PATCH 6/6] Partial Changes --- .../skript/bukkitutil/NamespacedUtils.java | 21 ++++++++++++++++ .../mannequin/elements/EffMannequinParts.java | 3 +-- .../mannequin/elements/ExprMannequinBody.java | 17 ++++--------- .../mannequin/elements/ExprMannequinCape.java | 17 ++++--------- .../elements/ExprMannequinElytra.java | 17 ++++--------- .../mannequin/elements/ExprMannequinSkin.java | 2 ++ .../skript/bukkit/utils/AdventureUtil.java | 24 +++++++++++++++++++ 7 files changed, 63 insertions(+), 38 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/utils/AdventureUtil.java diff --git a/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java b/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java index 67e5e1812cb..45b99b37d03 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java @@ -4,6 +4,8 @@ import ch.njol.skript.localization.Message; import ch.njol.skript.util.ValidationResult; import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.log.runtime.RuntimeErrorProducer; /** * Utility class for {@link NamespacedKey} @@ -89,4 +91,23 @@ public static boolean isValid(String string) { return checkValidation(string).valid(); } + /** + * Helper method for converting a {@link String} to {@link NamespacedKey} during runtime, and printing + * errors or warnings. + * @param producer The {@link RuntimeErrorProducer} instance to print an error or warning. + * @param string The {@link String} to convert to {@link NamespacedKey}. + * @return The resulting {@link NamespacedKey} if valid, otherwise {@code null}. + */ + public static @Nullable NamespacedKey getKeyWithErrors(RuntimeErrorProducer producer, String string) { + ValidationResult result = checkValidation(string); + String message = result.message(); + if (!result.valid()) { + producer.error(message); + return null; + } else if (message != null) { + producer.warning(message); + } + return result.data(); + } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java index c3daec04d71..12aed1eea51 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/EffMannequinParts.java @@ -76,8 +76,7 @@ public enum MannequinPart { RIGHT_SLEEVE("right sleeve"), PANTS("pants"), SLEEVES("sleeves"), - ALL("all") - ; + ALL("all"); public final String part; diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java index 4cd5da84494..eefeb852f8a 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinBody.java @@ -8,12 +8,10 @@ import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.util.ValidationResult; import ch.njol.util.coll.CollectionUtils; import io.papermc.paper.datacomponent.item.ResolvableProfile; import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; import net.kyori.adventure.key.Key; -import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; @@ -29,6 +27,8 @@ A namespaced key can be formatted as 'namespace:id' or 'id'. \ It can only contain one ':' to separate the namespace and the id. \ Only alphanumeric characters, periods, underscores, and dashes can be used. + Example: "minecraft:diamond_axe", namespace is "minecraft, and id is "diamond_axe". + Doing just "diamond_axe" is acceptable as well, as it defaults to the minecraft namespace. """) @Example("set the mannequin body of {_mannequin} to \"custom:body\"") @Example("clear the mannequin body key of last spawned mannequin") @@ -42,7 +42,7 @@ public static void register(SyntaxRegistry registry) { infoBuilder( ExprMannequinBody.class, String.class, - "mannequin body [texture] [key]", + "[mannequin] body [texture] (key|id)", "entities", false ).supplier(ExprMannequinBody::new) @@ -72,16 +72,9 @@ public static void register(SyntaxRegistry registry) { public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { Key key = null; if (delta != null) { - String string = (String) delta[0]; - ValidationResult result = NamespacedUtils.checkValidation(string); - String message = result.message(); - if (!result.valid()) { - error(message + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + key = NamespacedUtils.getKeyWithErrors(this, (String) delta[0]); + if (key == null) return; - } else if (message != null) { - warning(message); - } - key = result.data(); } for (Entity entity : getExpr().getArray(event)) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java index cb1945a50c1..0cbf78d1a13 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinCape.java @@ -8,12 +8,10 @@ import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.util.ValidationResult; import ch.njol.util.coll.CollectionUtils; import io.papermc.paper.datacomponent.item.ResolvableProfile; import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; import net.kyori.adventure.key.Key; -import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; @@ -29,6 +27,8 @@ A namespaced key can be formatted as 'namespace:id' or 'id'. \ It can only contain one ':' to separate the namespace and the id. \ Only alphanumeric characters, periods, underscores, and dashes can be used. + Example: "minecraft:diamond_axe", namespace is "minecraft, and id is "diamond_axe". + Doing just "diamond_axe" is acceptable as well, as it defaults to the minecraft namespace. """) @Example("set the mannequin cape of {_mannequin} to \"custom:cape\"") @Example("clear the mannequin cape key of last spawned mannequin") @@ -42,7 +42,7 @@ public static void register(SyntaxRegistry registry) { infoBuilder( ExprMannequinCape.class, String.class, - "mannequin cape [texture] [key]", + "[mannequin] cape [texture] (key|id)", "entities", false ).supplier(ExprMannequinCape::new) @@ -72,16 +72,9 @@ public static void register(SyntaxRegistry registry) { public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { Key key = null; if (delta != null) { - String string = (String) delta[0]; - ValidationResult result = NamespacedUtils.checkValidation(string); - String message = result.message(); - if (!result.valid()) { - error(message + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + key = NamespacedUtils.getKeyWithErrors(this, (String) delta[0]); + if (key == null) return; - } else if (message != null) { - warning(message); - } - key = result.data(); } for (Entity entity : getExpr().getArray(event)) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java index 1daa32a10d2..d5cf2f9bc8d 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinElytra.java @@ -8,12 +8,10 @@ import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.util.ValidationResult; import ch.njol.util.coll.CollectionUtils; import io.papermc.paper.datacomponent.item.ResolvableProfile; import io.papermc.paper.datacomponent.item.ResolvableProfile.SkinPatch; import net.kyori.adventure.key.Key; -import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Mannequin; import org.bukkit.event.Event; @@ -29,6 +27,8 @@ A namespaced key can be formatted as 'namespace:id' or 'id'. \ It can only contain one ':' to separate the namespace and the id. \ Only alphanumeric characters, periods, underscores, and dashes can be used. + Example: "minecraft:diamond_axe", namespace is "minecraft, and id is "diamond_axe". + Doing just "diamond_axe" is acceptable as well, as it defaults to the minecraft namespace. """) @Example("set the mannequin elytra of {_mannequin} to \"custom:elytra\"") @Example("clear the mannequin elytra key of last spawned mannequin") @@ -42,7 +42,7 @@ public static void register(SyntaxRegistry registry) { infoBuilder( ExprMannequinElytra.class, String.class, - "mannequin elytra [texture] [key]", + "[mannequin] elytra [texture] (key|id)", "entities", false ).supplier(ExprMannequinElytra::new) @@ -72,16 +72,9 @@ public static void register(SyntaxRegistry registry) { public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { Key key = null; if (delta != null) { - String string = (String) delta[0]; - ValidationResult result = NamespacedUtils.checkValidation(string); - String message = result.message(); - if (!result.valid()) { - error(message + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + key = NamespacedUtils.getKeyWithErrors(this, (String) delta[0]); + if (key == null) return; - } else if (message != null) { - warning(message); - } - key = result.data(); } for (Entity entity : getExpr().getArray(event)) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java index 858c25b7bc8..17b2bb42ba7 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java +++ b/src/main/java/org/skriptlang/skript/bukkit/entity/mannequin/elements/ExprMannequinSkin.java @@ -86,6 +86,8 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { playerProfile.complete(); profile = ResolvableProfile.resolvableProfile(playerProfile); } else if (delta[0] instanceof String string) { + if (string.length() < 10 || string.contains(" ")) + return; Builder builder = ResolvableProfile.resolvableProfile(); ProfileProperty property = new ProfileProperty("textures", string); builder.addProperty(property); diff --git a/src/main/java/org/skriptlang/skript/bukkit/utils/AdventureUtil.java b/src/main/java/org/skriptlang/skript/bukkit/utils/AdventureUtil.java new file mode 100644 index 00000000000..eb5f0d9469b --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/utils/AdventureUtil.java @@ -0,0 +1,24 @@ +package org.skriptlang.skript.bukkit.utils; + +import ch.njol.skript.util.chat.MessageComponent; +import net.kyori.adventure.text.Component; + +import java.util.Arrays; +import java.util.List; + +public class AdventureUtil { + + public static Component toComponent(MessageComponent origin) { + Component base; + if (origin.translation != null) { + String[] strings = origin.translation.split(":"); + String key = strings[0]; + base = Component.translatable(key, Arrays.copyOfRange(strings, 1, strings.length, Object[].class)); + } + } + + public static Component toComponent(List messageComponents) { + + } + +}