diff --git a/src/main/java/ch/njol/skript/classes/Serializer.java b/src/main/java/ch/njol/skript/classes/Serializer.java index bdd72ef28ff..2d278e8e3c5 100644 --- a/src/main/java/ch/njol/skript/classes/Serializer.java +++ b/src/main/java/ch/njol/skript/classes/Serializer.java @@ -16,9 +16,6 @@ import ch.njol.yggdrasil.Fields; import ch.njol.yggdrasil.YggdrasilSerializer; -/** - * @author Peter Güttinger - */ public abstract class Serializer extends YggdrasilSerializer { @Nullable @@ -79,10 +76,12 @@ public E newInstance(final Class c) { */ @Override public abstract Fields serialize(T o) throws NotSerializableException; - + @Override - public abstract void deserialize(T o, Fields f) throws StreamCorruptedException, NotSerializableException; - + public void deserialize(T o, Fields f) throws StreamCorruptedException, NotSerializableException { + throw new SkriptAPIException("deserialize(Object, Fields) has not been overridden in " + getClass() + " (serializer of " + info + ")"); + } + /** * Not currently used (everything happens on Bukkit's main thread). * 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..3af30b80ff4 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -112,7 +112,7 @@ public BukkitClasses() {} "set target block of player to minecraft:oak_leaves[distance=2;persistent=false]") .after("itemtype") .since("2.5") - .parser(new Parser() { + .parser(new Parser<>() { @Nullable @Override public BlockData parse(String input, ParseContext context) { @@ -129,22 +129,15 @@ public String toVariableNameString(BlockData o) { return "blockdata:" + o.getAsString(); } }) - .serializer(new Serializer() { + .serializer(new Serializer<>() { @Override - public Fields serialize(BlockData o) { - Fields f = new Fields(); - f.putObject("blockdata", o.getAsString()); - return f; + public Fields serialize(BlockData blockData) { + return Fields.singletonObject("blockdata", blockData.getAsString()); } @Override - public void deserialize(BlockData o, Fields f) { - assert false; - } - - @Override - protected BlockData deserialize(Fields f) throws StreamCorruptedException { - String data = f.getObject("blockdata", String.class); + protected BlockData deserialize(Fields fields) throws StreamCorruptedException { + String data = fields.getObject("blockdata", String.class); assert data != null; try { return Bukkit.createBlockData(data); @@ -174,13 +167,7 @@ protected boolean canBeInstantiated() { "set {home::%uuid of player%} to location of the player") .since("1.0") .defaultExpression(new EventValueExpression<>(Location.class)) - .parser(new Parser() { - @Override - @Nullable - public Location parse(final String s, final ParseContext context) { - return null; - } - + .parser(new Parser<>() { @Override public boolean canParse(final ParseContext context) { return false; @@ -201,7 +188,7 @@ public String toVariableNameString(final Location l) { public String getDebugMessage(final Location l) { return "(" + l.getWorld().getName() + ":" + l.getX() + "," + l.getY() + "," + l.getZ() + "|yaw=" + l.getYaw() + "/pitch=" + l.getPitch() + ")"; } - }).serializer(new Serializer() { + }).serializer(new Serializer<>() { @Override public Fields serialize(Location location) { Fields fields = new Fields(); @@ -220,11 +207,6 @@ public Fields serialize(Location location) { return fields; } - @Override - public void deserialize(final Location o, final Fields f) { - assert false; - } - @Override public Location deserialize(final Fields f) throws StreamCorruptedException { return new Location(f.getObject("world", World.class), @@ -272,13 +254,7 @@ public Location deserialize(final String s) { .examples("") .since("2.2-dev23") .defaultExpression(new EventValueExpression<>(Vector.class)) - .parser(new Parser() { - @Override - @Nullable - public Vector parse(final String s, final ParseContext context) { - return null; - } - + .parser(new Parser<>() { @Override public boolean canParse(final ParseContext context) { return false; @@ -309,11 +285,6 @@ public Fields serialize(Vector o) { return f; } - @Override - public void deserialize(Vector o, Fields f) { - assert false; - } - @Override public Vector deserialize(final Fields f) throws StreamCorruptedException { return new Vector(f.getPrimitive("x", double.class), f.getPrimitive("y", double.class), f.getPrimitive("z", double.class)); @@ -358,25 +329,18 @@ public World parse(final String s, final ParseContext context) { } @Override - public String toString(final World w, final int flags) { - return "" + w.getName(); + public String toString(World world, int flags) { + return world.getName(); } @Override - public String toVariableNameString(final World w) { - return "" + w.getName(); - } - }).serializer(new Serializer() { - @Override - public Fields serialize(final World w) { - final Fields f = new Fields(); - f.putObject("name", w.getName()); - return f; + public String toVariableNameString(World world) { + return world.getName(); } - + }).serializer(new Serializer<>() { @Override - public void deserialize(final World o, final Fields f) { - assert false; + public Fields serialize(World world) { + return Fields.singletonObject("name", world.getName()); } @Override @@ -385,13 +349,13 @@ public boolean canBeInstantiated() { } @Override - protected World deserialize(final Fields fields) throws StreamCorruptedException { - final String name = fields.getObject("name", String.class); + protected World deserialize(Fields fields) throws StreamCorruptedException { + String name = fields.getObject("name", String.class); assert name != null; - final World w = Bukkit.getWorld(name); - if (w == null) + World world = Bukkit.getWorld(name); + if (world == null) throw new StreamCorruptedException("Missing world " + name); - return w; + return world; } // return w.getName(); @@ -409,8 +373,8 @@ public boolean mustSyncDeserialization() { .property(Property.NAME, "A world's name, as text. Cannot be changed.", Skript.instance(), - ExpressionPropertyHandler.of(World::getName, String.class)) - ); + ExpressionPropertyHandler.of(World::getName, String.class) + )); Classes.registerClass(new InventoryClassInfo()); @@ -460,12 +424,6 @@ public boolean mustSyncDeserialization() { .since("1.0") .defaultExpression(new EventValueExpression<>(CommandSender.class)) .parser(new Parser<>() { - @Override - @Nullable - public CommandSender parse(final String s, final ParseContext context) { - return null; - } - @Override public boolean canParse(final ParseContext context) { return false; @@ -484,7 +442,8 @@ public String toVariableNameString(final CommandSender s) { .property(Property.NAME, "A command sender's name, as text. Cannot be changed.", Skript.instance(), - ExpressionPropertyHandler.of(CommandSender::getName, String.class))); + ExpressionPropertyHandler.of(CommandSender::getName, String.class) + )); Classes.registerClass(new NameableClassInfo()); @@ -492,7 +451,7 @@ public String toVariableNameString(final CommandSender s) { .name(ClassInfo.NO_DOC) .defaultExpression(new EventValueExpression<>(InventoryHolder.class)) .after("entity", "block") - .parser(new Parser() { + .parser(new Parser<>() { @Override public boolean canParse(ParseContext context) { return false; @@ -518,6 +477,7 @@ public String toVariableNameString(InventoryHolder holder) { return toString(holder, 0); } })); + Classes.registerClass(new EnumClassInfo<>(GameMode.class, "gamemode", "game modes", new SimpleLiteral<>(GameMode.SURVIVAL, true)) .user("game ?modes?") .name("Game Mode") @@ -543,81 +503,74 @@ public String toVariableNameString(InventoryHolder holder) { .after("damagecause")); Classes.registerClass(new ClassInfo<>(PotionEffect.class, "potioneffect") - .user("potion ?effects?") - .name("Potion Effect") - .description("A potion effect, including the potion effect type, tier and duration.") - .usage("speed of tier 1 for 10 seconds") - .since("2.5.2") - .parser(new Parser() { - - @Override - public boolean canParse(ParseContext context) { - return false; - } - - @Override - public String toString(PotionEffect potionEffect, int flags) { - return PotionEffectUtils.toString(potionEffect); - } - - @Override - public String toVariableNameString(PotionEffect o) { - return "potion_effect:" + o.getType().getName(); - } + .user("potion ?effects?") + .name("Potion Effect") + .description("A potion effect, including the potion effect type, tier and duration.") + .usage("speed of tier 1 for 10 seconds") + .since("2.5.2") + .parser(new Parser<>() { + @Override + public boolean canParse(ParseContext context) { + return false; + } - }) - .serializer(new Serializer() { - @Override - public Fields serialize(PotionEffect o) { - Fields fields = new Fields(); - fields.putObject("type", o.getType().getName()); - fields.putPrimitive("amplifier", o.getAmplifier()); - fields.putPrimitive("duration", o.getDuration()); - fields.putPrimitive("particles", o.hasParticles()); - fields.putPrimitive("ambient", o.isAmbient()); - return fields; - } + @Override + public String toString(PotionEffect potionEffect, int flags) { + return PotionEffectUtils.toString(potionEffect); + } - @Override - public void deserialize(PotionEffect o, Fields f) { - assert false; - } + @Override + public String toVariableNameString(PotionEffect o) { + return "potion_effect:" + o.getType().getName(); + } + }) + .serializer(new Serializer() { + @Override + public Fields serialize(PotionEffect o) { + Fields fields = new Fields(); + fields.putObject("type", o.getType().getName()); + fields.putPrimitive("amplifier", o.getAmplifier()); + fields.putPrimitive("duration", o.getDuration()); + fields.putPrimitive("particles", o.hasParticles()); + fields.putPrimitive("ambient", o.isAmbient()); + return fields; + } - @Override - protected PotionEffect deserialize(Fields fields) throws StreamCorruptedException { - String typeName = fields.getObject("type", String.class); - assert typeName != null; - PotionEffectType type = PotionEffectType.getByName(typeName); - if (type == null) - throw new StreamCorruptedException("Invalid PotionEffectType " + typeName); - int amplifier = fields.getPrimitive("amplifier", int.class); - int duration = fields.getPrimitive("duration", int.class); - boolean particles = fields.getPrimitive("particles", boolean.class); - boolean ambient = fields.getPrimitive("ambient", boolean.class); - return new PotionEffect(type, duration, amplifier, ambient, particles); - } + @Override + protected PotionEffect deserialize(Fields fields) throws StreamCorruptedException { + String typeName = fields.getObject("type", String.class); + assert typeName != null; + PotionEffectType type = PotionEffectType.getByName(typeName); + if (type == null) + throw new StreamCorruptedException("Invalid PotionEffectType " + typeName); + int amplifier = fields.getPrimitive("amplifier", int.class); + int duration = fields.getPrimitive("duration", int.class); + boolean particles = fields.getPrimitive("particles", boolean.class); + boolean ambient = fields.getPrimitive("ambient", boolean.class); + return new PotionEffect(type, duration, amplifier, ambient, particles); + } - @Override - public boolean mustSyncDeserialization() { - return false; - } + @Override + public boolean mustSyncDeserialization() { + return false; + } - @Override - protected boolean canBeInstantiated() { - return false; - } - })); + @Override + protected boolean canBeInstantiated() { + return false; + } + })); Registry petRegistry = BukkitUtils.getPotionEffectTypeRegistry(); if (petRegistry != null) { Classes.registerClass(new RegistryClassInfo<>(PotionEffectType.class, petRegistry, "potioneffecttype", "potion effect types", false) - .user("potion ?effect ?types?") - .name("Potion Effect Type") - .description("A potion effect type, e.g. 'strength' or 'swiftness'.") - .examples("apply swiftness 5 to the player", - "apply potion of speed 2 to the player for 60 seconds", - "remove invisibility from the victim") - .since("")); + .user("potion ?effect ?types?") + .name("Potion Effect Type") + .description("A potion effect type, e.g. 'strength' or 'swiftness'.") + .examples("apply swiftness 5 to the player", + "apply potion of speed 2 to the player for 60 seconds", + "remove invisibility from the victim") + .since("")); } else { Classes.registerClass(PotionEffectUtils.getLegacyClassInfo()); } @@ -640,13 +593,7 @@ protected boolean canBeInstantiated() { .usage("") .examples("") .since("2.0") - .parser(new Parser() { - @Override - @Nullable - public Chunk parse(final String s, final ParseContext context) { - return null; - } - + .parser(new Parser<>() { @Override public boolean canParse(final ParseContext context) { return false; @@ -662,33 +609,29 @@ public String toVariableNameString(final Chunk c) { return c.getWorld().getName() + ":" + c.getX() + "," + c.getZ(); } }) - .serializer(new Serializer() { + .serializer(new Serializer<>() { @Override - public Fields serialize(final Chunk c) { + public Fields serialize(Chunk chunk) { final Fields f = new Fields(); - f.putObject("world", c.getWorld()); - f.putPrimitive("x", c.getX()); - f.putPrimitive("z", c.getZ()); + f.putObject("world", chunk.getWorld()); + f.putPrimitive("x", chunk.getX()); + f.putPrimitive("z", chunk.getZ()); return f; } - @Override - public void deserialize(final Chunk o, final Fields f) { - assert false; - } - @Override public boolean canBeInstantiated() { return false; } @Override - protected Chunk deserialize(final Fields fields) throws StreamCorruptedException { - final World w = fields.getObject("world", World.class); - final int x = fields.getPrimitive("x", int.class), z = fields.getPrimitive("z", int.class); - if (w == null) - throw new StreamCorruptedException(); - return w.getChunkAt(x, z); + protected Chunk deserialize(Fields fields) throws StreamCorruptedException { + World world = fields.getObject("world", World.class); + if (world == null) + throw new StreamCorruptedException("Missing world"); + + int x = fields.getPrimitive("x", int.class), z = fields.getPrimitive("z", int.class); + return world.getChunkAt(x, z); } // return c.getWorld().getName() + ":" + c.getX() + "," + c.getZ(); @@ -731,24 +674,15 @@ public boolean mustSyncDeserialization() { Classes.registerClass(new ClassInfo<>(Material.class, "material") .name(ClassInfo.NO_DOC) .since("aliases-rework") - .serializer(new Serializer() { + .serializer(new Serializer<>() { @Override - public Fields serialize(Material o) { - Fields f = new Fields(); - f.putObject("i", o.ordinal()); - return f; - } - - @Override - public void deserialize(Material o, Fields f) { - assert false; + public Fields serialize(Material material) { + return Fields.singletonObject("i", material.ordinal()); } @Override - public Material deserialize(Fields f) throws StreamCorruptedException { - Material mat = allMaterials[(int) f.getPrimitive("i")]; - assert mat != null; // Hope server owner didn't mod too much... - return mat; + public Material deserialize(Fields fields) throws StreamCorruptedException { + return fields.mapPrimitive("i", int.class, i -> allMaterials[i]); } @Override @@ -788,25 +722,19 @@ protected boolean canBeInstantiated() { .description("A server icon that was loaded using the load server icon effect.") .examples("") .since("2.3") - .parser(new Parser() { - @Override - @Nullable - public CachedServerIcon parse(final String s, final ParseContext context) { - return null; - } - + .parser(new Parser<>() { @Override - public boolean canParse(final ParseContext context) { + public boolean canParse(ParseContext context) { return false; } @Override - public String toString(final CachedServerIcon o, int flags) { + public String toString(CachedServerIcon o, int flags) { return "server icon"; } @Override - public String toVariableNameString(final CachedServerIcon o) { + public String toVariableNameString(CachedServerIcon o) { return "server icon"; } })); @@ -833,13 +761,7 @@ public String toVariableNameString(final CachedServerIcon o) { "launch trailing flickering star colored purple, yellow, blue, green and red fading to pink at target entity", "launch ball large colored red, purple and white fading to light green and black at player's location with duration 1" ).since("2.4") - .parser(new Parser() { - @Override - @Nullable - public FireworkEffect parse(String input, ParseContext context) { - return null; - } - + .parser(new Parser<>() { @Override public boolean canParse(ParseContext context) { return false; @@ -908,19 +830,19 @@ public String[] getPatterns() { }; Classes.registerClass(new ClassInfo<>(GameRule.class, "gamerule") - .user("gamerules?") - .name("Gamerule") - .description("A gamerule") - .usage(gameRuleParser.getCombinedPatterns()) - .since("2.5") - .requiredPlugins("Minecraft 1.13 or newer") - .supplier(GameRule.values()) - .parser(gameRuleParser) - .property(Property.NAME, - "A gamerule's name, as text. Cannot be changed.", - Skript.instance(), - ExpressionPropertyHandler.of(GameRule::getName, String.class)) - ); + .user("gamerules?") + .name("Gamerule") + .description("A gamerule") + .usage(gameRuleParser.getCombinedPatterns()) + .since("2.5") + .requiredPlugins("Minecraft 1.13 or newer") + .supplier(GameRule.values()) + .parser(gameRuleParser) + .property(Property.NAME, + "A gamerule's name, as text. Cannot be changed.", + Skript.instance(), + ExpressionPropertyHandler.of(GameRule::getName, String.class) + )); Classes.registerClass(new ClassInfo<>(EnchantmentOffer.class, "enchantmentoffer") .user("enchant[ment][ ]offers?") @@ -930,7 +852,7 @@ public String[] getPatterns() { "\tset enchant offer 1 to sharpness 1", "\tset the cost of enchant offer 1 to 10 levels") .since("2.5") - .parser(new Parser() { + .parser(new Parser<>() { @Override public boolean canParse(ParseContext context) { return false; @@ -950,8 +872,8 @@ public String toVariableNameString(EnchantmentOffer eo) { Classes.registerClass(new RegistryClassInfo<>(Attribute.class, Registry.ATTRIBUTE, "attributetype", "attribute types") .user("attribute ?types?") .name("Attribute Type") - .description("Represents the type of an attribute. Note that this type does not contain any numerical values." - + "See attribute types for more info.", + .description("Represents the type of an attribute. Note that this type does not contain any numerical values." + + "See attribute types for more info.", "NOTE: Minecraft namespaces are supported, ex: 'minecraft:generic.attack_damage'.") .since("2.5")); @@ -989,10 +911,10 @@ public String toVariableNameString(EnchantmentOffer eo) { .since("2.8.0")); Classes.registerClass(new EnumClassInfo<>(EntityUnleashEvent.UnleashReason.class, "unleashreason", "unleash reasons") - .user("unleash ?(reason|cause)s?") - .name("Unleash Reason") - .description("Represents an unleash reason of an unleash event.") - .since("2.10")); + .user("unleash ?(reason|cause)s?") + .name("Unleash Reason") + .description("Represents an unleash reason of an unleash event.") + .since("2.10")); Classes.registerClass(new EnumClassInfo<>(ItemFlag.class, "itemflag", "item flags") .user("item ?flags?") @@ -1007,33 +929,56 @@ public String toVariableNameString(EnchantmentOffer eo) { .since("2.10")); Classes.registerClass(new EnumClassInfo<>(ChangeReason.class, "experiencecooldownchangereason", "experience cooldown change reasons") - .user("(experience|[e]xp) cooldown change (reason|cause)s?") - .name("Experience Cooldown Change Reason") - .description("Represents a change reason of an experience cooldown change event.") - .since("2.10")); + .user("(experience|[e]xp) cooldown change (reason|cause)s?") + .name("Experience Cooldown Change Reason") + .description("Represents a change reason of an experience cooldown change event.") + .since("2.10")); Classes.registerClass(new RegistryClassInfo<>(Villager.Type.class, Registry.VILLAGER_TYPE, "villagertype", "villager types") - .user("villager ?types?") - .name("Villager Type") - .description("Represents the different types of villagers. These are usually the biomes a villager can be from.") - .after("biome") - .since("2.10")); + .user("villager ?types?") + .name("Villager Type") + .description("Represents the different types of villagers. These are usually the biomes a villager can be from.") + .after("biome") + .since("2.10")); Classes.registerClass(new RegistryClassInfo<>(Villager.Profession.class, Registry.VILLAGER_PROFESSION, "villagerprofession", "villager professions") - .user("villager ?professions?") - .name("Villager Profession") - .description("Represents the different professions of villagers.") - .since("2.10")); + .user("villager ?professions?") + .name("Villager Profession") + .description("Represents the different professions of villagers.") + .since("2.10")); if (Skript.classExists("org.bukkit.entity.EntitySnapshot")) { Classes.registerClass(new ClassInfo<>(EntitySnapshot.class, "entitysnapshot") - .user("entity ?snapshots?") - .name("Entity Snapshot") - .description("Represents a snapshot of an entity's data.", - "This includes all of the data associated with an entity (its name, health, attributes, etc.), at the time this expression is used. " - + "Essentially, these are a way to create templates for entities.", - "Individual attributes of a snapshot cannot be modified or retrieved.") - .since("2.10") + .user("entity ?snapshots?") + .name("Entity Snapshot") + .description("Represents a snapshot of an entity's data.", + "This includes all of the data associated with an entity (its name, health, attributes, etc.), at the time this expression is used. " + + "Essentially, these are a way to create templates for entities.", + "Individual attributes of a snapshot cannot be modified or retrieved.") + .since("2.10") + .parser(new Parser<>() { + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(EntitySnapshot snapshot, int flags) { + return EntityUtils.toSkriptEntityData(snapshot.getEntityType()).toString() + " snapshot"; + } + + @Override + public String toVariableNameString(EntitySnapshot snapshot) { + return toString(snapshot, 0); + } + })); + } + + Classes.registerClass(new ClassInfo<>(WorldBorder.class, "worldborder") + .user("world ?borders?") + .name("World Border") + .description("Represents the border of a world or player.") + .since("2.11") .parser(new Parser<>() { @Override public boolean canParse(ParseContext context) { @@ -1041,49 +986,24 @@ public boolean canParse(ParseContext context) { } @Override - public String toString(EntitySnapshot snapshot, int flags) { - return EntityUtils.toSkriptEntityData(snapshot.getEntityType()).toString() + " snapshot"; + public String toString(WorldBorder border, int flags) { + if (border.getWorld() == null) + return "virtual world border"; + return "world border of world named '" + border.getWorld().getName() + "'"; } @Override - public String toVariableNameString(EntitySnapshot snapshot) { - return toString(snapshot, 0); + public String toVariableNameString(WorldBorder border) { + return toString(border, 0); } }) - ); - } - - Classes.registerClass(new ClassInfo<>(WorldBorder.class, "worldborder") - .user("world ?borders?") - .name("World Border") - .description("Represents the border of a world or player.") - .since("2.11") - .parser(new Parser() { - @Override - public boolean canParse(ParseContext context) { - return false; - } - - @Override - public String toString(WorldBorder border, int flags) { - if (border.getWorld() == null) - return "virtual world border"; - return "world border of world named '" + border.getWorld().getName() + "'"; - } - - @Override - public String toVariableNameString(WorldBorder border) { - return toString(border, 0); - } - }) - .defaultExpression(new EventValueExpression<>(WorldBorder.class))); + .defaultExpression(new EventValueExpression<>(WorldBorder.class))); Classes.registerClass(new ClassInfo<>(org.bukkit.block.banner.Pattern.class, "bannerpattern") - .user("banner ?patterns?") - .name("Banner Pattern") - .description("Represents a banner pattern.") - .since("2.10") - ); + .user("banner ?patterns?") + .name("Banner Pattern") + .description("Represents a banner pattern.") + .since("2.10")); ClassInfo patternTypeInfo; Registry patternRegistry = Bukkit.getRegistry(PatternType.class); @@ -1104,12 +1024,12 @@ public String toVariableNameString(WorldBorder border) { throw new RuntimeException(e); } } + Classes.registerClass(patternTypeInfo - .user("banner ?pattern ?types?") - .name("Banner Pattern Type") - .description("Represents the various banner patterns that can be applied to a banner.") - .since("2.10") - ); + .user("banner ?pattern ?types?") + .name("Banner Pattern Type") + .description("Represents the various banner patterns that can be applied to a banner.") + .since("2.10")); if (Skript.classExists("io.papermc.paper.entity.TeleportFlag")) Classes.registerClass(new EnumClassInfo<>(SkriptTeleportFlag.class, "teleportflag", "teleport flags") @@ -1119,26 +1039,22 @@ public String toVariableNameString(WorldBorder border) { .since("2.10")); Classes.registerClass(new ClassInfo<>(Vehicle.class, "vehicle") - .user("vehicles?") - .name("Vehicle") - .description("Represents a vehicle.") - .since("2.10.2") - .changer(new EntityChanger()) - ); + .user("vehicles?") + .name("Vehicle") + .description("Represents a vehicle.") + .since("2.10.2") + .changer(new EntityChanger())); Classes.registerClass(new EnumClassInfo<>(EquipmentSlot.class, "equipmentslot", "equipment slots") - .user("equipment ?slots?") - .name("Equipment Slot") - .description("Represents an equipment slot of an entity.") - .since("2.11") - ); + .user("equipment ?slots?") + .name("Equipment Slot") + .description("Represents an equipment slot of an entity.") + .since("2.11")); Classes.registerClass(new EnumClassInfo<>(VillagerCareerChangeEvent.ChangeReason.class, "villagercareerchangereason", "villager career change reasons") - .user("(villager )?career ?change ?reasons?") - .name("Villager Career Change Reason") - .description("Represents a reason why a villager changed its career.") - .since("2.12") - ); - + .user("(villager )?career ?change ?reasons?") + .name("Villager Career Change Reason") + .description("Represents a reason why a villager changed its career.") + .since("2.12")); } } diff --git a/src/main/java/ch/njol/yggdrasil/Fields.java b/src/main/java/ch/njol/yggdrasil/Fields.java index 2739d1b9c48..7b38df0788a 100644 --- a/src/main/java/ch/njol/yggdrasil/Fields.java +++ b/src/main/java/ch/njol/yggdrasil/Fields.java @@ -17,6 +17,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.function.Function; @NotThreadSafe public final class Fields implements Iterable { @@ -62,7 +63,7 @@ public Class getType() { assert type != null; return isPrimitiveValue ? Tag.getPrimitiveFromWrapper(type).type : type; } - + @Nullable public Object getObject() throws StreamCorruptedException { if (isPrimitiveValue) @@ -216,7 +217,63 @@ public Fields(Object object, @Nullable Yggdrasil yggdrasil) throws NotSerializab } private static final Map, Collection> cache = new HashMap<>(); - + + /** + * Creates a Fields object with a single object field. + * + * @param fieldID The id of the field + * @param value The value of the field + * @return A Fields object with the given field defined + */ + public static Fields singletonObject(String fieldID, @Nullable Object value) { + Fields fields = new Fields(); + fields.putObject(fieldID, value); + return fields; + } + + /** + * Creates a Fields object with a single primitive field. + * + * @param fieldID The id of the field + * @param value The value of the field + * @return A Fields object with the given field defined + */ + public static Fields singletonPrimitive(String fieldID, Object value) { + Fields fields = new Fields(); + fields.putPrimitive(fieldID, value); + return fields; + } + + /** + * Maps the object stored in the given field through the provided function. + * + * @param fieldID The id of the field + * @param type The expected type of the field + * @param function The mapping function + * @param The type of the field + * @param The return type of the mapping function + * @return The result of applying the mapping function to the field's value + * @throws StreamCorruptedException If the field does not exist or is of an unexpected type + */ + public R mapObject(String fieldID, Class type, Function function) throws StreamCorruptedException { + return function.apply(getObject(fieldID, type)); + } + + /** + * Maps the primitive stored in the given field through the provided function. + * + * @param fieldID The id of the field + * @param type The expected type of the field + * @param function The mapping function + * @param The type of the field + * @param The return type of the mapping function + * @return The result of applying the mapping function to the field's value + * @throws StreamCorruptedException If the field does not exist or is of an unexpected type + */ + public R mapPrimitive(String fieldID, Class type, Function function) throws StreamCorruptedException { + return function.apply(getPrimitive(fieldID, type)); + } + /** * Gets all serializable fields of the provided class, including superclasses. *