Skip to content

Commit d6e5425

Browse files
authored
Merge pull request #1 from Kiber2009/feature/recipes
Add custom crafting recipes
2 parents 0f92331 + 76cbeaa commit d6e5425

10 files changed

Lines changed: 215 additions & 3 deletions

File tree

src/main/java/io/github/kiber2009/plugin/contentapi/ContentApiPlugin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public void onEnable() {
2121
instance = this;
2222

2323
getServer().getPluginManager().registerEvents(new ItemsManager(), this);
24+
getServer().getPluginManager().registerEvents(new RecipesManager(), this);
2425

2526
getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands ->
2627
commands.registrar().register(Commands.literal("contentapi")
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.github.kiber2009.plugin.contentapi;
2+
3+
import io.github.kiber2009.plugin.contentapi.api.recipe.CustomCraftingRecipe;
4+
import io.github.kiber2009.plugin.contentapi.registry.recipe.RecipeGlobalRegistry;
5+
import org.bukkit.event.EventHandler;
6+
import org.bukkit.event.Listener;
7+
import org.bukkit.event.inventory.PrepareItemCraftEvent;
8+
9+
final class RecipesManager implements Listener {
10+
@EventHandler
11+
private static void onPrepareItemCraft(final PrepareItemCraftEvent event) {
12+
if (event.isRepair())
13+
return;
14+
15+
final CustomCraftingRecipe recipe = RecipeGlobalRegistry.CRAFTING.get(event.getInventory().getMatrix());
16+
if (recipe != null)
17+
event.getInventory().setResult(recipe.getResult());
18+
}
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.github.kiber2009.plugin.contentapi.api.recipe;
2+
3+
import org.bukkit.inventory.ItemStack;
4+
import org.jspecify.annotations.NonNull;
5+
import org.jspecify.annotations.Nullable;
6+
7+
import java.util.function.Predicate;
8+
9+
public interface CustomCraftingRecipe extends CustomRecipe, Predicate<@Nullable ItemStack @NonNull []> {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.github.kiber2009.plugin.contentapi.api.recipe;
2+
3+
import org.bukkit.inventory.ItemStack;
4+
import org.jetbrains.annotations.Contract;
5+
import org.jspecify.annotations.NonNull;
6+
7+
public interface CustomRecipe {
8+
@Contract(pure = true)
9+
@NonNull ItemStack getResult();
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.github.kiber2009.plugin.contentapi.api.recipe.choice;
2+
3+
import io.github.kiber2009.plugin.contentapi.api.item.CustomItem;
4+
import org.bukkit.inventory.ItemStack;
5+
import org.jetbrains.annotations.Contract;
6+
import org.jspecify.annotations.NonNull;
7+
import org.jspecify.annotations.Nullable;
8+
9+
import java.util.function.Predicate;
10+
11+
public class CustomItemRecipeChoice implements Predicate<@Nullable ItemStack> {
12+
private final CustomItem item;
13+
14+
public CustomItemRecipeChoice(final @NonNull CustomItem item) {
15+
this.item = item;
16+
}
17+
18+
@Override
19+
@Contract(value = "null -> false", pure = true)
20+
public boolean test(final @Nullable ItemStack stack) {
21+
return item.match(stack);
22+
}
23+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package io.github.kiber2009.plugin.contentapi.api.recipe.crafting;
2+
3+
import io.github.kiber2009.plugin.contentapi.api.recipe.CustomCraftingRecipe;
4+
import org.bukkit.inventory.ItemStack;
5+
import org.jetbrains.annotations.Contract;
6+
import org.jspecify.annotations.NonNull;
7+
import org.jspecify.annotations.Nullable;
8+
9+
import java.util.function.Predicate;
10+
11+
public class CustomShapedCraftingRecipe implements CustomCraftingRecipe {
12+
private static final byte[][] OFFSETS = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
13+
14+
private final ItemStack result;
15+
private final Predicate<ItemStack>[] matrix;
16+
17+
public CustomShapedCraftingRecipe(final @NonNull Predicate<@Nullable ItemStack> @NonNull [] matrix,
18+
final @NonNull ItemStack result) {
19+
if (matrix.length != 4 && matrix.length != 9)
20+
throw new IllegalArgumentException("Invalid matrix size");
21+
this.matrix = matrix;
22+
this.result = result;
23+
}
24+
25+
@Override
26+
@Contract(pure = true)
27+
public @NonNull ItemStack getResult() {
28+
return result.clone();
29+
}
30+
31+
@Override
32+
@Contract(pure = true)
33+
public boolean test(final @Nullable ItemStack @NonNull [] matrix) {
34+
if (matrix.length == 4 && this.matrix.length == 9)
35+
return false;
36+
37+
if (matrix.length == this.matrix.length) {
38+
for (int i = 0; i < matrix.length; i++)
39+
if (!this.matrix[i].test(matrix[i]))
40+
return false;
41+
return true;
42+
}
43+
44+
for (final byte[] off : OFFSETS) {
45+
boolean fits = true;
46+
47+
for (int i = 0; i < 2 && fits; i++)
48+
for (int j = 0; j < 2; j++)
49+
if (!this.matrix[(off[0] + i) * 3 + off[1] + j].test(matrix[i * 2 + j])) {
50+
fits = false;
51+
break;
52+
}
53+
54+
if (fits)
55+
return true;
56+
}
57+
return false;
58+
}
59+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package io.github.kiber2009.plugin.contentapi.api.recipe.crafting;
2+
3+
import io.github.kiber2009.plugin.contentapi.api.recipe.CustomCraftingRecipe;
4+
import org.bukkit.inventory.ItemStack;
5+
import org.jetbrains.annotations.Contract;
6+
import org.jspecify.annotations.NonNull;
7+
import org.jspecify.annotations.Nullable;
8+
9+
import java.util.function.Predicate;
10+
11+
public class CustomShapelessCraftingRecipe implements CustomCraftingRecipe {
12+
private final ItemStack result;
13+
private final Predicate<ItemStack>[] ingredients;
14+
15+
@SafeVarargs
16+
public CustomShapelessCraftingRecipe(final @NonNull ItemStack result,
17+
final @NonNull Predicate<@NonNull ItemStack> @NonNull ... ingredients) {
18+
if (ingredients.length > 9)
19+
throw new IllegalArgumentException("Too many ingredients");
20+
this.result = result;
21+
this.ingredients = ingredients;
22+
}
23+
24+
@Override
25+
@Contract(pure = true)
26+
public @NonNull ItemStack getResult() {
27+
return result.clone();
28+
}
29+
30+
@Override
31+
@Contract(pure = true)
32+
public boolean test(final @Nullable ItemStack @NonNull [] matrix) {
33+
if (matrix.length < ingredients.length)
34+
return false;
35+
36+
final boolean[] used = new boolean[ingredients.length];
37+
int usedCount = 0;
38+
39+
for (final ItemStack elem : matrix) {
40+
if (elem == null)
41+
continue;
42+
43+
boolean found = false;
44+
for (int i = 0; i < ingredients.length; i++)
45+
if (!used[i] && ingredients[i].test(elem)) {
46+
used[i] = true;
47+
usedCount++;
48+
found = true;
49+
break;
50+
}
51+
52+
if (!found)
53+
return false;
54+
}
55+
56+
return usedCount == ingredients.length;
57+
}
58+
}

src/main/java/io/github/kiber2009/plugin/contentapi/registry/GlobalRegistry.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111
import java.util.Objects;
1212
import java.util.Set;
1313

14-
public sealed class GlobalRegistry<T> permits ItemGlobalRegistry {
14+
public class GlobalRegistry<T> {
1515
@SuppressWarnings("StaticInitializerReferencesSubClass")
1616
public static final ItemGlobalRegistry ITEMS = new ItemGlobalRegistry();
1717

18-
private final Map<NamespacedKey, T> map = new HashMap<>();
18+
protected final Map<NamespacedKey, T> map = new HashMap<>();
1919

2020
protected void registerItem(final @NonNull NamespacedKey key, final @NonNull T value) {
2121
if (map.containsKey(key))
2222
throw new IllegalStateException("Duplicate key " + key);
2323
map.put(key, value);
2424
}
2525

26-
public void register(final @NonNull LocalRegistry<T> registry) {
26+
public void register(final @NonNull LocalRegistry<? extends T> registry) {
2727
for (final NamespacedKey key : registry.keySet())
2828
registerItem(key, Objects.requireNonNull(registry.get(key)));
2929
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.github.kiber2009.plugin.contentapi.registry.recipe;
2+
3+
import io.github.kiber2009.plugin.contentapi.api.recipe.CustomCraftingRecipe;
4+
import org.bukkit.inventory.ItemStack;
5+
import org.jetbrains.annotations.Contract;
6+
import org.jspecify.annotations.NonNull;
7+
import org.jspecify.annotations.Nullable;
8+
9+
public final class CraftingRecipeGlobalRegistry extends RecipeGlobalRegistry<CustomCraftingRecipe> {
10+
CraftingRecipeGlobalRegistry() {
11+
}
12+
13+
@Contract(pure = true)
14+
public @Nullable CustomCraftingRecipe get(final @Nullable ItemStack @NonNull [] matrix) {
15+
for (final CustomCraftingRecipe recipe : map.values())
16+
if (recipe.test(matrix))
17+
return recipe;
18+
return null;
19+
}
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.github.kiber2009.plugin.contentapi.registry.recipe;
2+
3+
import io.github.kiber2009.plugin.contentapi.api.recipe.CustomRecipe;
4+
import io.github.kiber2009.plugin.contentapi.registry.GlobalRegistry;
5+
6+
public sealed class RecipeGlobalRegistry<T extends CustomRecipe> extends GlobalRegistry<T>
7+
permits CraftingRecipeGlobalRegistry {
8+
@SuppressWarnings("StaticInitializerReferencesSubClass")
9+
public static final CraftingRecipeGlobalRegistry CRAFTING = new CraftingRecipeGlobalRegistry();
10+
11+
RecipeGlobalRegistry() {
12+
}
13+
}

0 commit comments

Comments
 (0)