Skip to content
This repository has been archived by the owner on Apr 12, 2022. It is now read-only.

Commit

Permalink
add item scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed May 21, 2018
1 parent dbb2e4c commit 8049dd6
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 5 deletions.
Expand Up @@ -28,6 +28,7 @@
import com.denizenscript.denizen2sponge.spongeevents.Denizen2SpongeLoadingEvent;
import com.denizenscript.denizen2sponge.spongescripts.AdvancementScript;
import com.denizenscript.denizen2sponge.spongescripts.GameCommandScript;
import com.denizenscript.denizen2sponge.spongescripts.ItemScript;
import com.denizenscript.denizen2sponge.tags.handlers.*;
import com.denizenscript.denizen2sponge.tags.objects.*;
import com.denizenscript.denizen2sponge.utilities.GameRules;
Expand All @@ -47,6 +48,7 @@

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
* Main plugin class for Denizen2Sponge.
Expand Down Expand Up @@ -79,11 +81,12 @@ public static Text parseColor(String inp) {
return TextSerializers.formattingCode(Denizen2Sponge.colorChar).deserialize(inp);
}

public static HashMap<String, InventoryTag> rememberedInventories = new HashMap<>();
public static final Map<String, InventoryTag> rememberedInventories = new HashMap<>();

@Inject
public Logger logger;

public static final Map<String, ItemScript> itemScripts = new HashMap<>();

static {
YAMLConfiguration tconfig = null;
Expand Down Expand Up @@ -256,6 +259,7 @@ public void onServerStart(GamePreInitializationEvent event) {
// Sponge Script Types
Denizen2Core.register("command", GameCommandScript::new);
Denizen2Core.register("advancement", AdvancementScript::new);
Denizen2Core.register("item", ItemScript::new);
// Tag Types
Denizen2Core.customSaveLoaders.put("BlockTypeTag", BlockTypeTag::getFor);
Denizen2Core.customSaveLoaders.put("CuboidTag", CuboidTag::getFor);
Expand Down
@@ -0,0 +1,212 @@
package com.denizenscript.denizen2sponge.spongescripts;

import com.denizenscript.denizen2core.Denizen2Core;
import com.denizenscript.denizen2core.arguments.Argument;
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.MapTag;
import com.denizenscript.denizen2core.tags.objects.ScriptTag;
import com.denizenscript.denizen2core.utilities.Action;
import com.denizenscript.denizen2core.utilities.CoreUtilities;
import com.denizenscript.denizen2core.utilities.ErrorInducedException;
import com.denizenscript.denizen2core.utilities.Tuple;
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.ItemTag;
import com.denizenscript.denizen2sponge.utilities.DataKeys;
import com.denizenscript.denizen2sponge.utilities.flags.FlagMap;
import com.denizenscript.denizen2sponge.utilities.flags.FlagMapDataImpl;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.key.Key;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.item.ItemType;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.text.Text;

import java.util.*;

public class ItemScript extends CommandScript {

// <--[explanation]
// @Since 0.5.0
// @Name Item Scripts
// @Group Script Types
// @Description
// An item script is a type of script that fully defines a specific in-game item stack.
// Keys in an item script define the various properties of an item stack.
//
// An item script can be used in place of any normal item, by putting the name of the item script
// where a script expects an item type. A script may block this from user input by
// requiring a valid ItemTypeTag input, which will not recognize an item script.
//
// The item script name may not be the same as an existing item type name.
//
// ItemStacks generated from an item script will remember their type using flag "_d2_script".
// To stop this from occurring, set key "plain" to "true".
//
// Set key "static" to "true" on the item script to make it load once at startup and simply be duplicated on all usages.
// If static is false or unspecified, the item script will be loaded from data at each call requesting it.
// This is likely preferred if any tags are used within the script.
//
// Quantity values should be specified in the script requesting the item (For example, in a give command)
// as that is likely very localized. The item stack given directly by the item script system will have a quantity of 1.
//
// All options listed below are used to define the item's specific details. They all support tags on input.
//
// Set key "material" directly to an ItemTag of the basic item type to use. You may list an item type, or an existing item.
// Be careful to not list the item script within itself, even indirectly, as this can cause recursion errors.
//
// Set key "display name" directly to a TextTag value of the name the item should have.
//
// Set key "lore" as a list key of lines the item should have.
// If you wish to dynamically structure the list, see the "other values" option for specifying that.
//
// Set key "flags" as a section and within it put all flags keyed by name and with the value that each flag should hold.
// If you wish to dynamically structure the mapping, see the "keys" option for specifying that.
//
// To specify other values, create a section labeled "keys" and within it put any valid item keys.
// TODO: Create and reference an explanation of basic item keys.
// -->

public ItemScript(String name, YAMLConfiguration section) {
super(name, section);
}

@Override
public boolean init() {
if (super.init()) {
try {
prepValues();
Action<String> error = (es) -> {
throw new ErrorInducedException(es);
};
if (contents.contains("static") && BooleanTag.getFor(error, contents.getString("static")).getInternal()) {
staticItem = generateItem(null);
}
}
catch (ErrorInducedException ex) {
Debug.error("Item generation for " + ColorSet.emphasis + title + ColorSet.warning + ": " + ex.getMessage());
return false;
}
Denizen2Sponge.itemScripts.put(CoreUtilities.toLowerCase(title), this);
return true;
}
return false;
}

public ItemStack staticItem = null;

public ItemStack getItemCopy(CommandQueue queue) {
if (staticItem != null) {
return staticItem;
}
return generateItem(queue);
}

public Argument displayName, plain, material;

public List<Argument> lore;

public List<Tuple<String, Argument>> otherValues, flags;

public void prepValues() {
Action<String> error = (es) -> {
throw new ErrorInducedException(es);
};
if (Sponge.getRegistry().getType(ItemType.class, title).isPresent()) {
Debug.error("Item script " + title + " may be unusable: a base item type exists with that name!");
}
if (contents.contains("display name")) {
displayName = Denizen2Core.splitToArgument(contents.getString("display name"), true, true, error);
}
if (contents.contains("plain")) {
plain = Denizen2Core.splitToArgument(contents.getString("plain"), true, true, error);
}
if (contents.contains("material")) {
material = Denizen2Core.splitToArgument(contents.getString("material"), true, true, error);
}
else {
throw new ErrorInducedException("Material key is missing. Cannot generate!");
}
if (contents.contains("lore")) {
List<String> listLore = contents.getStringList("lore");
lore = new ArrayList<>();
for (String line : listLore) {
lore.add(Denizen2Core.splitToArgument(line, true, true, error));
}
}
if (contents.contains("flags")) {
flags = new ArrayList<>();
YAMLConfiguration sec = contents.getConfigurationSection("flags");
for (StringHolder key : sec.getKeys(false)) {
Argument arg = Denizen2Core.splitToArgument(sec.getString(key.str), true, true, error);
flags.add(new Tuple<>(CoreUtilities.toUpperCase(key.low), arg));
}
}
if (contents.contains("keys")) {
otherValues = new ArrayList<>();
YAMLConfiguration sec = contents.getConfigurationSection("keys");
for (StringHolder key : sec.getKeys(false)) {
Argument arg = Denizen2Core.splitToArgument(sec.getString(key.str), true, true, error);
otherValues.add(new Tuple<>(CoreUtilities.toUpperCase(key.low), arg));
}
}
}

public AbstractTagObject parseVal(CommandQueue queue, Argument arg) {
Action<String> error = (es) -> {
throw new ErrorInducedException(es);
};
return arg.parse(queue, new HashMap<>(), getDebugMode(), error);
}

public ItemStack generateItem(CommandQueue queue) {
Action<String> error = (es) -> {
throw new ErrorInducedException(es);
};
ItemStack.Builder its = ItemStack.builder().from(ItemTag.getFor(error, parseVal(queue, material)).getInternal()).quantity(1);
if (displayName != null) {
its = its.add(Keys.DISPLAY_NAME, Denizen2Sponge.parseColor(parseVal(queue, displayName).toString()));
}
if (lore != null) {
List<Text> loreVal = new ArrayList<>();
for (Argument arg : lore) {
loreVal.add(Denizen2Sponge.parseColor(parseVal(queue, arg).toString()));
}
its.add(Keys.ITEM_LORE, loreVal);
}
MapTag flagsMap = new MapTag();
if (flags != null) {
for (Tuple<String, Argument> flagVal : flags) {
flagsMap.getInternal().put(flagVal.one, parseVal(queue, flagVal.two));
}
}
if (plain == null || !BooleanTag.getFor(error, parseVal(queue, plain)).getInternal()) {
flagsMap.getInternal().put("_d2_script", new ScriptTag(this));
}
ItemStack toRet = its.build();
if (otherValues != null) {
for (Tuple<String, Argument> input : otherValues) {
Key k = DataKeys.getKeyForName(input.one);
if (k == null) {
throw new ErrorInducedException("Key '" + input.one + "' does not seem to exist.");
}
DataKeys.tryApply(toRet, k, parseVal(queue, input.two), error);
}
}
if (!flagsMap.getInternal().isEmpty()) {
toRet.offer(new FlagMapDataImpl(new FlagMap(flagsMap)));
}
return toRet;
}

@Override
public boolean isExecutable(String section) {
return false;
}
}
Expand Up @@ -5,15 +5,20 @@
import com.denizenscript.denizen2core.tags.objects.*;
import com.denizenscript.denizen2core.utilities.Action;
import com.denizenscript.denizen2core.utilities.CoreUtilities;
import com.denizenscript.denizen2core.utilities.ErrorInducedException;
import com.denizenscript.denizen2core.utilities.Function2;
import com.denizenscript.denizen2sponge.Denizen2Sponge;
import com.denizenscript.denizen2sponge.spongescripts.ItemScript;
import com.denizenscript.denizen2sponge.utilities.DataKeys;
import com.denizenscript.denizen2sponge.utilities.flags.FlagHelper;
import com.denizenscript.denizen2sponge.utilities.flags.FlagMap;
import com.denizenscript.denizen2sponge.utilities.flags.FlagMapDataImpl;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.key.Key;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.type.SkullType;
import org.spongepowered.api.data.type.SkullTypes;
import org.spongepowered.api.item.ItemType;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.profile.property.ProfileProperty;

Expand Down Expand Up @@ -44,6 +49,23 @@ public ItemStack getInternal() {

public final static HashMap<String, Function2<TagData, AbstractTagObject, AbstractTagObject>> handlers = new HashMap<>();

public ItemScript getSourceScript() {
Optional<FlagMap> fm = internal.get(FlagHelper.FLAGMAP);
if (fm.isPresent()) {
MapTag flags = fm.get().flags;
if (flags.getInternal().containsKey("_d2_script")) {
AbstractTagObject scriptObj = flags.getInternal().get("_d2_script");
if (scriptObj instanceof ScriptTag) {
ScriptTag script = (ScriptTag) scriptObj;
if (script.getInternal() instanceof ItemScript) {
return (ItemScript) script.getInternal();
}
}
}
}
return null;
}

static {
// <--[tag]
// @Since 0.3.0
Expand All @@ -52,9 +74,37 @@ public ItemStack getInternal() {
// @Group General Information
// @ReturnType MapTag
// @Returns a list of all data keys and their values for the entity.
// TODO: Create and reference an explanation of basic item keys.
// -->
handlers.put("data", (dat, obj) -> DataKeys.getAllKeys(((ItemTag) obj).internal));
// <--[tag]
// @Since 0.5.0
// @Name ItemTag.is_script
// @Updated 2018/05/21
// @Group General Information
// @ReturnType BooleanTag
// @Returns whether the item was sourced from a script.
// -->
handlers.put("is_script", (dat, obj) -> new BooleanTag(((ItemTag) obj).getSourceScript() != null));
// <--[tag]
// @Since 0.5.0
// @Name ItemTag.script
// @Updated 2018/05/21
// @Group General Information
// @ReturnType ScriptTag
// @Returns the script this item tag was created with, if any.
// -->
handlers.put("script", (dat, obj) -> {
ItemScript src = ((ItemTag) obj).getSourceScript();
if (src == null) {
if (!dat.hasFallback()) {
dat.error.run("Item was not sourced from a script.");
}
return new NullTag();
}
return new ScriptTag(src);
});
// <--[tag]
// @Since 0.3.0
// @Name ItemTag.flag[<TextTag>]
// @Updated 2016/11/24
Expand Down Expand Up @@ -93,6 +143,7 @@ public ItemStack getInternal() {
// @Group General Information
// @ReturnType Dynamic
// @Returns the value of the specified key on the entity.
// TODO: Create and reference an explanation of basic item keys.
// -->
handlers.put("get", (dat, obj) -> {
String keyName = dat.getNextModifier().toString();
Expand Down Expand Up @@ -272,12 +323,17 @@ public ItemStack getInternal() {
// @Group General Information
// @ReturnType ItemTag
// @Returns a copy of the item, with the specified data adjustments.
// TODO: Create and reference an explanation of basic item keys.
// -->
handlers.put("with", (dat, obj) -> {
ItemStack its = ((ItemTag) obj).internal.createSnapshot().createStack();
MapTag toApply = MapTag.getFor(dat.error, dat.getNextModifier());
for (Map.Entry<String, AbstractTagObject> a : toApply.getInternal().entrySet()) {
DataKeys.tryApply(its, DataKeys.getKeyForName(a.getKey()), a.getValue(), dat.error);
Key k = DataKeys.getKeyForName(a.getKey());
if (k == null) {
dat.error.run("Key '" + a.getKey() + "' does not seem to exist.");
}
DataKeys.tryApply(its, k, a.getValue(), dat.error);
}
return new ItemTag(its);
});
Expand Down Expand Up @@ -311,16 +367,33 @@ public ItemStack getInternal() {

public static ItemTag getFor(Action<String> error, String text) {
List<String> split = CoreUtilities.split(text, '/', 3);
ItemTypeTag type = ItemTypeTag.getFor(error, split.get(0));
int q = 1;
if (split.size() > 1) {
q = (int) IntegerTag.getFor(error, split.get(1)).getInternal();
}
ItemStack its = ItemStack.of(type.getInternal(), q);
Optional<ItemType> optItemType = Sponge.getRegistry().getType(ItemType.class, text);
ItemStack its;
if (optItemType.isPresent()) {
its = ItemStack.of(optItemType.get(), q);
}
else {
String tlow = CoreUtilities.toLowerCase(text);
if (Denizen2Sponge.itemScripts.containsKey(tlow)) {
its = Denizen2Sponge.itemScripts.get(tlow).getItemCopy(null);
}
else {
error.run("Invalid item type '" + text + "'");
return null;
}
}
if (split.size() > 2) {
MapTag toApply = MapTag.getFor(error, split.get(2));
for (Map.Entry<String, AbstractTagObject> a : toApply.getInternal().entrySet()) {
DataKeys.tryApply(its, DataKeys.getKeyForName(a.getKey()), a.getValue(), error);
Key k = DataKeys.getKeyForName(a.getKey());
if (k == null) {
error.run("Key '" + a.getKey() + "' does not seem to exist.");
}
DataKeys.tryApply(its, k, a.getValue(), error);
}
}
return new ItemTag(its);
Expand Down

0 comments on commit 8049dd6

Please sign in to comment.