From e39b04683be8191e16dcc93ff7c9717e3ce29873 Mon Sep 17 00:00:00 2001 From: Xenmai Date: Tue, 6 Feb 2018 01:28:14 +0100 Subject: [PATCH] Advancement Scripts and Commands Lacks additional testing, some polishing and some documentation. Also lacks commands for Score-type advancement criteria., but it's a start! --- .../denizen2sponge/Denizen2Sponge.java | 4 + .../player/GrantAdvancementCommand.java | 66 ++++++ .../player/RevokeAdvancementCommand.java | 66 ++++++ .../spongescripts/AdvancementScript.java | 195 ++++++++++++++++++ .../denizen2sponge/utilities/Utilities.java | 15 +- 5 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/denizenscript/denizen2sponge/commands/player/GrantAdvancementCommand.java create mode 100644 src/main/java/com/denizenscript/denizen2sponge/commands/player/RevokeAdvancementCommand.java create mode 100644 src/main/java/com/denizenscript/denizen2sponge/spongescripts/AdvancementScript.java diff --git a/src/main/java/com/denizenscript/denizen2sponge/Denizen2Sponge.java b/src/main/java/com/denizenscript/denizen2sponge/Denizen2Sponge.java index 8aacb6b..6fef9c5 100644 --- a/src/main/java/com/denizenscript/denizen2sponge/Denizen2Sponge.java +++ b/src/main/java/com/denizenscript/denizen2sponge/Denizen2Sponge.java @@ -26,6 +26,7 @@ import com.denizenscript.denizen2sponge.spongecommands.ExCommand; import com.denizenscript.denizen2sponge.spongeevents.Denizen2SpongeLoadedEvent; import com.denizenscript.denizen2sponge.spongeevents.Denizen2SpongeLoadingEvent; +import com.denizenscript.denizen2sponge.spongescripts.AdvancementScript; import com.denizenscript.denizen2sponge.spongescripts.GameCommandScript; import com.denizenscript.denizen2sponge.tags.handlers.*; import com.denizenscript.denizen2sponge.tags.objects.*; @@ -155,11 +156,13 @@ public void onServerStart(GamePreInitializationEvent event) { Denizen2Core.register(new FeedCommand()); Denizen2Core.register(new GamemodeCommand()); Denizen2Core.register(new GiveCommand()); + Denizen2Core.register(new GrantAdvancementCommand()); Denizen2Core.register(new HotbarCommand()); Denizen2Core.register(new KickCommand()); Denizen2Core.register(new NarrateCommand()); Denizen2Core.register(new PardonCommand()); Denizen2Core.register(new RemoveBossBarCommand()); + Denizen2Core.register(new RevokeAdvancementCommand()); Denizen2Core.register(new TabListCommand()); Denizen2Core.register(new TakeCommand()); Denizen2Core.register(new TellCommand()); @@ -249,6 +252,7 @@ public void onServerStart(GamePreInitializationEvent event) { Denizen2Core.register(new WorldTagBase()); // Sponge Script Types Denizen2Core.register("command", GameCommandScript::new); + Denizen2Core.register("advancement", AdvancementScript::new); // Tag Types Denizen2Core.customSaveLoaders.put("BlockTypeTag", BlockTypeTag::getFor); Denizen2Core.customSaveLoaders.put("CuboidTag", CuboidTag::getFor); diff --git a/src/main/java/com/denizenscript/denizen2sponge/commands/player/GrantAdvancementCommand.java b/src/main/java/com/denizenscript/denizen2sponge/commands/player/GrantAdvancementCommand.java new file mode 100644 index 0000000..5966bd4 --- /dev/null +++ b/src/main/java/com/denizenscript/denizen2sponge/commands/player/GrantAdvancementCommand.java @@ -0,0 +1,66 @@ +package com.denizenscript.denizen2sponge.commands.player; + +import com.denizenscript.denizen2core.commands.AbstractCommand; +import com.denizenscript.denizen2core.commands.CommandEntry; +import com.denizenscript.denizen2core.commands.CommandQueue; +import com.denizenscript.denizen2core.utilities.debugging.ColorSet; +import com.denizenscript.denizen2core.utilities.debugging.Debug; +import com.denizenscript.denizen2sponge.tags.objects.PlayerTag; +import com.denizenscript.denizen2sponge.utilities.Utilities; +import org.spongepowered.api.advancement.Advancement; + +public class GrantAdvancementCommand extends AbstractCommand { + + // <--[command] + // @Since 0.4.0 + // @Name grantadvancement + // @Arguments + // @Short grants an advancement to a player. + // @Updated 2018/02/06 + // @Group Player + // @Minimum 2 + // @Maximum 2 + // @Description + // Grants an advancement to a player. + // @Example + // # This example grants the advancement "iron_man" to the player. + // - grantadvancement iron_man + // --> + + @Override + public String getName() { + return "grantadvancement"; + } + + @Override + public String getArguments() { + return " "; + } + + @Override + public int getMinimumArguments() { + return 2; + } + + @Override + public int getMaximumArguments() { + return 2; + } + + @Override + public void execute(CommandQueue queue, CommandEntry entry) { + PlayerTag player = PlayerTag.getFor(queue.error, entry.getArgumentObject(queue, 0)); + String id = entry.getArgumentObject(queue, 1).toString(); + Advancement advancement = (Advancement) Utilities.getTypeWithDefaultPrefix(Advancement.class, id); + if (advancement == null) { + Debug.error("There's no registered advancement that matches the specified id!"); + return; + } + player.getOnline(queue.error).getProgress(advancement).grant(); + if (queue.shouldShowGood()) { + queue.outGood("Granting advancement '" + ColorSet.emphasis + advancement.getId() + + ColorSet.good + "' to player '" + ColorSet.emphasis + player.debug() + + ColorSet.good + "'!"); + } + } +} diff --git a/src/main/java/com/denizenscript/denizen2sponge/commands/player/RevokeAdvancementCommand.java b/src/main/java/com/denizenscript/denizen2sponge/commands/player/RevokeAdvancementCommand.java new file mode 100644 index 0000000..92fc44f --- /dev/null +++ b/src/main/java/com/denizenscript/denizen2sponge/commands/player/RevokeAdvancementCommand.java @@ -0,0 +1,66 @@ +package com.denizenscript.denizen2sponge.commands.player; + +import com.denizenscript.denizen2core.commands.AbstractCommand; +import com.denizenscript.denizen2core.commands.CommandEntry; +import com.denizenscript.denizen2core.commands.CommandQueue; +import com.denizenscript.denizen2core.utilities.debugging.ColorSet; +import com.denizenscript.denizen2core.utilities.debugging.Debug; +import com.denizenscript.denizen2sponge.tags.objects.PlayerTag; +import com.denizenscript.denizen2sponge.utilities.Utilities; +import org.spongepowered.api.advancement.Advancement; + +public class RevokeAdvancementCommand extends AbstractCommand { + + // <--[command] + // @Since 0.4.0 + // @Name revokeadvancement + // @Arguments + // @Short revokes an advancement from a player. + // @Updated 2018/02/06 + // @Group Player + // @Minimum 2 + // @Maximum 2 + // @Description + // Revokes an advancement from a player. + // @Example + // # This example revokes the advancement "iron_man" from the player. + // - revokeadvancement iron_man + // --> + + @Override + public String getName() { + return "revokeadvancement"; + } + + @Override + public String getArguments() { + return " "; + } + + @Override + public int getMinimumArguments() { + return 2; + } + + @Override + public int getMaximumArguments() { + return 2; + } + + @Override + public void execute(CommandQueue queue, CommandEntry entry) { + PlayerTag player = PlayerTag.getFor(queue.error, entry.getArgumentObject(queue, 0)); + String id = entry.getArgumentObject(queue, 1).toString(); + Advancement advancement = (Advancement) Utilities.getTypeWithDefaultPrefix(Advancement.class, id); + if (advancement == null) { + Debug.error("There's no registered advancement that matches the specified id!"); + return; + } + player.getOnline(queue.error).getProgress(advancement).revoke(); + if (queue.shouldShowGood()) { + queue.outGood("Revoking advancement '" + ColorSet.emphasis + advancement.getId() + + ColorSet.good + "' from player '" + ColorSet.emphasis + player.debug() + + ColorSet.good + "'!"); + } + } +} diff --git a/src/main/java/com/denizenscript/denizen2sponge/spongescripts/AdvancementScript.java b/src/main/java/com/denizenscript/denizen2sponge/spongescripts/AdvancementScript.java new file mode 100644 index 0000000..c250ef3 --- /dev/null +++ b/src/main/java/com/denizenscript/denizen2sponge/spongescripts/AdvancementScript.java @@ -0,0 +1,195 @@ +package com.denizenscript.denizen2sponge.spongescripts; + +import com.denizenscript.denizen2core.Denizen2Core; +import com.denizenscript.denizen2core.commands.CommandQueue; +import com.denizenscript.denizen2core.scripts.CommandScript; +import com.denizenscript.denizen2core.tags.AbstractTagObject; +import com.denizenscript.denizen2core.tags.objects.BooleanTag; +import com.denizenscript.denizen2core.tags.objects.IntegerTag; +import com.denizenscript.denizen2core.tags.objects.NumberTag; +import com.denizenscript.denizen2core.utilities.debugging.ColorSet; +import com.denizenscript.denizen2core.utilities.debugging.Debug; +import com.denizenscript.denizen2core.utilities.yaml.StringHolder; +import com.denizenscript.denizen2core.utilities.yaml.YAMLConfiguration; +import com.denizenscript.denizen2sponge.Denizen2Sponge; +import com.denizenscript.denizen2sponge.tags.objects.FormattedTextTag; +import com.denizenscript.denizen2sponge.tags.objects.ItemTypeTag; +import com.denizenscript.denizen2sponge.utilities.Utilities; +import com.flowpowered.math.vector.Vector2d; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.advancement.*; +import org.spongepowered.api.advancement.criteria.AdvancementCriterion; +import org.spongepowered.api.advancement.criteria.ScoreAdvancementCriterion; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.advancement.AdvancementTreeEvent; +import org.spongepowered.api.event.game.GameRegistryEvent; + +import java.util.HashMap; +import java.util.Optional; + +public class AdvancementScript extends CommandScript { + + public static HashMap currentAdvancementScripts = new HashMap<>(); + + // <--[explanation] + // @Since 0.4.0 + // @Name Advancement Scripts + // @Group Script Types + // @Description + // An advancement script is a script that adds new advancements to the server. + // It is identified with the type "advancement". + // Expected keys: id (string), name (string, optional), criteria (map), display + // (advancement type), title (FormattedTextTag), description (FormattedTextTag), + // announce (boolean), show_toast (boolean), hidden (boolean), icon (item type), + // parent (id, only for children advancements), tree_id (string, only for root + // advancements), tree_name (string, only for root advancements, optional), + // position_x (number), and position_y (number). + // TODO: Add "Related information" such as criteria formatting, advancement types and examples. + // --> + + public AdvancementScript(String name, YAMLConfiguration section) { + super(name, section); + } + + @Override + public boolean isExecutable(String section) { + return false; + } + + @Override + public boolean init() { + if (super.init()) { + register(); + return true; + } + return false; + } + + public Advancement advancement; + + public AdvancementTree tree = null; + + public Vector2d position; + + public void register() { + Sponge.getEventManager().registerListeners(Denizen2Sponge.instance, this); + String id = contents.getString("id"); + if (Denizen2Core.getImplementation().generalDebug()) { + Debug.good("Registering advancement script " + ColorSet.emphasis + id + + ColorSet.good + " to Denizen2Sponge..."); + } + Advancement.Builder builder = Advancement.builder().id(id); + if (contents.contains("name")) { + builder.name(contents.getString("name")); + } + AdvancementCriterion criterion = AdvancementCriterion.EMPTY; + YAMLConfiguration criteria = contents.getConfigurationSection("criteria"); + for (StringHolder strh : criteria.getKeys(false)) { + String critNumber = strh.low; + String critName = criteria.getString(critNumber + ".name"); + AdvancementCriterion.BaseBuilder toAdd = AdvancementCriterion.builder().name(critName); + if (criteria.contains(critName + ".score")) { + boolean score = BooleanTag.getFor(Debug::error, + criteria.getString(critName + ".score")).getInternal(); + if (score) { + IntegerTag goal = IntegerTag.getFor(Debug::error, + criteria.getString(critName + ".goal")); + ((ScoreAdvancementCriterion.Builder) toAdd).goal((int) goal.getInternal()); + } + } + criterion = criterion.and(toAdd.build()); + } + builder.criterion(criterion); + String typeId = contents.getString("display"); + Optional type = Sponge.getRegistry().getType(AdvancementType.class, typeId); + if (!type.isPresent()) { + Debug.error("The display specified is not a valid advancement type!"); + return; + } + DisplayInfo.Builder info = DisplayInfo.builder().type(type.get()); + AbstractTagObject title = Denizen2Core.splitToArgument( + contents.getString("title"), false, false, Debug::error) + .parse(new CommandQueue(), new HashMap<>(), getDebugMode(), Debug::error); + if (title instanceof FormattedTextTag) { + info.title(((FormattedTextTag) title).getInternal()); + } + else { + info.title(Denizen2Sponge.parseColor(title.toString())); + } + AbstractTagObject desc = Denizen2Core.splitToArgument( + contents.getString("description"), false, false, Debug::error) + .parse(new CommandQueue(), new HashMap<>(), getDebugMode(), Debug::error); + if (desc instanceof FormattedTextTag) { + info.title(((FormattedTextTag) desc).getInternal()); + } + else { + info.title(Denizen2Sponge.parseColor(desc.toString())); + } + BooleanTag announce = BooleanTag.getFor(Debug::error, contents.getString("announce")); + info.announceToChat(announce.getInternal()); + BooleanTag show = BooleanTag.getFor(Debug::error, contents.getString("show_toast")); + info.showToast(show.getInternal()); + BooleanTag hidden = BooleanTag.getFor(Debug::error, contents.getString("hidden")); + info.hidden(hidden.getInternal()); + ItemTypeTag icon = ItemTypeTag.getFor(Debug::error, contents.getString("icon")); + info.icon(icon.getInternal()); + builder.displayInfo(info.build()); + if (criteria.contains("parent")) { + String parentId = contents.getString("parent"); + Advancement parent = (Advancement) Utilities.getTypeWithDefaultPrefix(Advancement.class, parentId); + if (parent == null) { + Debug.error("There's no registered advancement for the parent id specified!"); + return; + } + builder.parent(parent); + advancement = builder.build(); + } + else { + advancement = builder.build(); + String treeId = contents.getString("tree_id"); + AdvancementTree.Builder treeBuilder = AdvancementTree.builder().id(treeId); + if (contents.contains("tree_name")) { + treeBuilder.name(contents.getString("tree_name")); + } + if (contents.contains("tree_background")) { + treeBuilder.background(contents.getString("tree_background")); + } + treeBuilder.rootAdvancement(advancement); + tree = treeBuilder.build(); + } + currentAdvancementScripts.put(id, this); + NumberTag x = NumberTag.getFor(Debug::error, contents.getString("x_position")); + NumberTag y = NumberTag.getFor(Debug::error, contents.getString("y_position")); + position = new Vector2d(x.getInternal(), y.getInternal()); + } + + public boolean isTreeRoot() { + return tree != null; + } + + @Listener + public void onRegisterAdvancementTrees(GameRegistryEvent.Register event) { + if (isTreeRoot()) { + event.register(tree); + Debug.good("Registering advancement tree '" + tree.getId() + "' to Sponge..."); + } + } + + @Listener + public void onRegisterAdvancements(GameRegistryEvent.Register event) { + event.register(advancement); + Debug.good("Registering advancement '" + advancement.getId() + "' to Sponge..."); + } + + @Listener + public void onGenerateTreeLayout(AdvancementTreeEvent.GenerateLayout event) { + if (isTreeRoot() && event.getTree() == tree) { + for (TreeLayoutElement element : event.getLayout().getElements()) { + Vector2d pos = currentAdvancementScripts + .get(Utilities.getIdWithoutDefaultPrefix(element.getAdvancement().getId())).position; + element.setPosition(pos); + } + Debug.good("Updating layout for tree '" + tree.getId() + "'..."); + } + } +} diff --git a/src/main/java/com/denizenscript/denizen2sponge/utilities/Utilities.java b/src/main/java/com/denizenscript/denizen2sponge/utilities/Utilities.java index b962a76..3eb7967 100644 --- a/src/main/java/com/denizenscript/denizen2sponge/utilities/Utilities.java +++ b/src/main/java/com/denizenscript/denizen2sponge/utilities/Utilities.java @@ -40,7 +40,16 @@ public static boolean flagIsValidAndNotExpired(Action error, MapTag flag } public static String getIdWithoutDefaultPrefix(String id) { - return id.startsWith("minecraft:") ? id.substring("minecraft:".length()) : id; + if (id.startsWith("minecraft")) { + return id.substring("minecraft:".length()); + } + if (id.startsWith("sponge")) { + return id.substring("sponge:".length()); + } + if (id.startsWith("denizen2sponge")) { + return id.substring("denizen2sponge:".length()); + } + return id; } public static Object getTypeWithDefaultPrefix(Class clazz, String name) { @@ -53,6 +62,10 @@ public static Object getTypeWithDefaultPrefix(Class clazz, String name) { return opt.get(); } opt = Sponge.getRegistry().getType(clazz, "sponge:" + name); + if (opt.isPresent()) { + return opt.get(); + } + opt = Sponge.getRegistry().getType(clazz, "denizen2sponge:" + name); return opt.orElse(null); } }