Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recipe Support #7150

Open
wants to merge 20 commits into
base: dev/feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/ch/njol/skript/Skript.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
import org.junit.runner.notification.Failure;
import org.skriptlang.skript.bukkit.SkriptMetrics;
import org.skriptlang.skript.bukkit.displays.DisplayModule;
import org.skriptlang.skript.bukkit.recipes.RecipeModule;
import org.skriptlang.skript.lang.comparator.Comparator;
import org.skriptlang.skript.lang.comparator.Comparators;
import org.skriptlang.skript.lang.converter.Converter;
Expand Down Expand Up @@ -555,6 +556,7 @@ public void onEnable() {
getAddonInstance().loadClasses("org.skriptlang.skript.bukkit", "misc");
// todo: become proper module once registry api is merged
DisplayModule.load();
RecipeModule.load();
} catch (final Exception e) {
exception(e, "Could not load required .class files: " + e.getLocalizedMessage());
setEnabled(false);
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.player.PlayerToggleFlightEvent;
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
import org.bukkit.event.server.ServerCommandEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
Expand Down Expand Up @@ -1393,6 +1394,14 @@ public Player get(final PrepareItemCraftEvent e) {
return null;
}
}, 0);

EventValues.registerEventValue(PrepareItemCraftEvent.class, Recipe.class, new Getter<Recipe, PrepareItemCraftEvent>() {
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
@Override
public @Nullable Recipe get(PrepareItemCraftEvent event) {
return event.getRecipe();
}
}, EventValues.TIME_NOW);

// CraftEvents - recipe namespaced key strings
EventValues.registerEventValue(CraftItemEvent.class, String.class, new Getter<String, CraftItemEvent>() {
@Nullable
Expand Down Expand Up @@ -1422,6 +1431,14 @@ public ItemStack get(CraftItemEvent e) {
return e.getRecipe().getResult();
}
}, 0);

EventValues.registerEventValue(CraftItemEvent.class, Recipe.class, new Getter<Recipe, CraftItemEvent>() {
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
@Override
public @Nullable Recipe get(CraftItemEvent event) {
return event.getRecipe();
}
}, EventValues.TIME_NOW);

//InventoryOpenEvent
EventValues.registerEventValue(InventoryOpenEvent.class, Player.class, new Getter<Player, InventoryOpenEvent>() {
@Override
Expand Down Expand Up @@ -1991,5 +2008,13 @@ public Entity[] get(BlockDropItemEvent event) {
return event.getItems().toArray(Entity[]::new);
}
}, EventValues.TIME_NOW);

// PlayerRecipeDiscoverEvent
EventValues.registerEventValue(PlayerRecipeDiscoverEvent.class, Recipe.class, new Getter<Recipe, PlayerRecipeDiscoverEvent>() {
@Override
public @Nullable Recipe get(PlayerRecipeDiscoverEvent event) {
return Bukkit.getRecipe(event.getRecipe());
}
}, EventValues.TIME_NOW);
}
}
124 changes: 124 additions & 0 deletions src/main/java/ch/njol/skript/util/NamespacedUtils.java
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package ch.njol.skript.util;

import ch.njol.skript.Skript;
import ch.njol.util.Pair;
import com.google.common.collect.Sets;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.NamespacedKey;

import java.util.Set;

public class NamespacedUtils {

private static final Set<Character> LEGAL_NAMESPACE_CHARS = Sets.newHashSet(ArrayUtils.toObject("abcdefghijklmnopqrstuvwxyz0123456789._-/".toCharArray()));

/**
* Gets a namespaced key. This method will try to get existing keys first, but if that fails
* it will create the key in Skript's namespace.
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
* @param key the unparsed key
* @param usingMinecraft whether to have it as Skript or Minecraft namespace
* @return the resulting NamespacedKey
*/
public static NamespacedKey getNamespacedKey(String key, Boolean usingMinecraft) {
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
NamespacedKey namespacedKey;
if (usingMinecraft)
namespacedKey = NamespacedKey.fromString(key);
else
namespacedKey = NamespacedKey.fromString(key, Skript.getInstance());
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
if (namespacedKey != null)
return namespacedKey;
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
NamespacedKey convertedKey = createNamespacedKey(key, usingMinecraft);
if (!Skript.testing())
Skript.info("The key provided '" + key + "' has been converted to '" + convertedKey.toString() + "' due to invalid characters." +
"\n\tValid characters are a-z, 0-9, -, _ and .");
return convertedKey;
}

/**
* Creates a namespaced key in Skript's namespace encoded to avoid the character limitations of a normal key.
* This key will be created in Skript's namespace.
*
* @param key The key to use
* @param usingMinecraft whether to have it as Skript or Minecraft's namespace
* @return a NamespacedKey with the encoded key in corresponding Namespace
*/
public static NamespacedKey createNamespacedKey(String key, Boolean usingMinecraft) {
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
// TODO: add tests for this
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
StringBuilder encodedKeyBuilder = new StringBuilder();
// keys must be all lowercase
key = key.toLowerCase();
key = key.replace(' ', '_');
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
int keyLength = key.length();
for (int i = 0; i < keyLength; i++) {
char currentChar = key.charAt(i);
// if this character is legal to use in a namespace key
if (LEGAL_NAMESPACE_CHARS.contains(currentChar)) {
// if the original string had a ".x" in it, we need to escape it
// so decoding doesn't think it's a hex sequence
if (currentChar == '.' && key.charAt(i + 1) == 'x') {
i += 1; // skip the "x"
encodedKeyBuilder.append(".x");
encodedKeyBuilder.append(Integer.toHexString('.'));
encodedKeyBuilder.append(".x");
encodedKeyBuilder.append(Integer.toHexString('x'));
// if we're not at the end and the next char is a legal char, add the trailing dot
// to represent the end of the hex sequence
if (i != (keyLength - 1) && LEGAL_NAMESPACE_CHARS.contains(key.charAt(i + 1)))
encodedKeyBuilder.append('.');
} else {
// we are dealing with a legal character, so we can just append it
encodedKeyBuilder.append(currentChar);
}
} else {
// add ".x(hex code)" to the encoded key
encodedKeyBuilder.append(".x");
encodedKeyBuilder.append(Integer.toHexString(currentChar));
// only add the trailing dot if the next character is a legal character
if (i != (keyLength - 1) && LEGAL_NAMESPACE_CHARS.contains(key.charAt(i + 1)))
encodedKeyBuilder.append('.');
}
}
if (usingMinecraft)
return NamespacedKey.fromString(encodedKeyBuilder.toString());
return NamespacedKey.fromString(encodedKeyBuilder.toString(), Skript.getInstance());
}

/**
* Decodes a NamespacedKey encoded by #getNamespacedKey
*
* @param namespacedKey the namespaced key to decode
* @return a Pair with the first element as the namespace and the second as the decoded key
*/
public static Pair<String, String> decodeNamespacedKey(NamespacedKey namespacedKey) {
// TODO: add tests for this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uncertain about this as I have not found a use for it. Maybe Sovde or Pikachu can shed some more light on it when they review.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well if you're gonna add it you might as well add tests :)

String encodedKey = namespacedKey.getKey();
StringBuilder decodedKeyBuilder = new StringBuilder();
int encodedKeyLength = encodedKey.length();
int lastCharIndex = encodedKeyLength - 1;
for (int i = 0; i < encodedKeyLength; i++) {
char currentChar = encodedKey.charAt(i);
// if we are encountering a ".x" hex sequence
if (i != lastCharIndex && currentChar == '.' && encodedKey.charAt(i + 1) == 'x') {
i += 2; // skip the ".x" so it isn't part of our hex string
StringBuilder hexString = new StringBuilder();
// The hex sequence continues until a . is encountered or we reach the end of the string
while (i <= lastCharIndex && encodedKey.charAt(i) != '.') {
hexString.append(encodedKey.charAt(i));
i++;
}
// if the . was the start of another ".x" hex sequence, back up by 1 character
if (i <= lastCharIndex && encodedKey.charAt(i + 1) == 'x')
i--;
// parse the hex sequence to a char
char decodedChar = (char) Long.parseLong(hexString.toString(), 16);
decodedKeyBuilder.append(decodedChar);
} else {
// this is just a normal character, not a hex sequence
// so we can just append it
decodedKeyBuilder.append(currentChar);
}
}
return new Pair<>(namespacedKey.getNamespace(), decodedKeyBuilder.toString());
}

}
Loading