mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-11 01:41:47 +01:00
chore: vastly simplified recipe manager behavior
This commit is contained in:
parent
c3a71ad10f
commit
2233ec8362
@ -8,6 +8,7 @@ import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.minestom.demo.block.TestBlockHandler;
|
||||
import net.minestom.demo.block.placement.DripstonePlacementRule;
|
||||
import net.minestom.demo.commands.*;
|
||||
import net.minestom.demo.recipe.ShapelessRecipe;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.event.server.ServerListPingEvent;
|
||||
@ -19,8 +20,7 @@ import net.minestom.server.item.ItemComponent;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.ping.ResponseData;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.RecipeCategory;
|
||||
import net.minestom.server.recipe.RecipeBookCategory;
|
||||
import net.minestom.server.utils.identity.NamedAndIdentified;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
|
||||
@ -120,28 +120,13 @@ public class Main {
|
||||
//responseData.setPlayersHidden(true);
|
||||
});
|
||||
|
||||
var ironBlockRecipe = new Recipe(
|
||||
"minestom:test",
|
||||
new Recipe.Shaped("", RecipeCategory.Crafting.MISC, 2, 2,
|
||||
List.of(
|
||||
new Recipe.Ingredient(Material.IRON_INGOT),
|
||||
new Recipe.Ingredient(Material.IRON_INGOT),
|
||||
new Recipe.Ingredient(Material.IRON_INGOT),
|
||||
new Recipe.Ingredient(Material.IRON_INGOT)
|
||||
), ItemStack.of(Material.IRON_BLOCK), true));
|
||||
MinecraftServer.getRecipeManager().addRecipe(ironBlockRecipe);
|
||||
var recipe = new Recipe(
|
||||
"minestom:test2",
|
||||
new Recipe.Shapeless("abc",
|
||||
RecipeCategory.Crafting.MISC,
|
||||
List.of(
|
||||
new Recipe.Ingredient(Material.DIRT)
|
||||
),
|
||||
ItemStack.builder(Material.GOLD_BLOCK)
|
||||
.set(ItemComponent.CUSTOM_NAME, Component.text("abc"))
|
||||
.build())
|
||||
);
|
||||
MinecraftServer.getRecipeManager().addRecipe(recipe);
|
||||
MinecraftServer.getRecipeManager().addRecipe(new ShapelessRecipe(
|
||||
RecipeBookCategory.CRAFTING_MISC,
|
||||
List.of(Material.DIRT),
|
||||
ItemStack.builder(Material.GOLD_BLOCK)
|
||||
.set(ItemComponent.CUSTOM_NAME, Component.text("abc"))
|
||||
.build()
|
||||
));
|
||||
|
||||
new PlayerInit().init();
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
package net.minestom.demo.recipe;
|
||||
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.recipe.Ingredient;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.RecipeBookCategory;
|
||||
import net.minestom.server.recipe.display.RecipeDisplay;
|
||||
import net.minestom.server.recipe.display.SlotDisplay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ShapelessRecipe(
|
||||
@NotNull RecipeBookCategory recipeBookCategory,
|
||||
@NotNull List<Material> ingredients,
|
||||
@NotNull ItemStack result
|
||||
) implements Recipe {
|
||||
|
||||
@Override
|
||||
public @NotNull List<RecipeDisplay> createRecipeDisplays() {
|
||||
return List.of(new RecipeDisplay.CraftingShapeless(
|
||||
ingredients.stream().map(item -> (SlotDisplay) new SlotDisplay.Item(item)).toList(),
|
||||
new SlotDisplay.ItemStack(result),
|
||||
new SlotDisplay.Item(Material.CRAFTING_TABLE)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Ingredient> craftingRequirements() {
|
||||
return List.of(new Ingredient(ingredients));
|
||||
}
|
||||
|
||||
}
|
@ -72,7 +72,6 @@ import net.minestom.server.network.packet.server.play.data.WorldPos;
|
||||
import net.minestom.server.network.player.ClientSettings;
|
||||
import net.minestom.server.network.player.GameProfile;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.RecipeManager;
|
||||
import net.minestom.server.registry.DynamicRegistry;
|
||||
import net.minestom.server.scoreboard.BelowNameTag;
|
||||
@ -340,27 +339,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
||||
// Commands
|
||||
refreshCommands();
|
||||
|
||||
// Recipes start
|
||||
{
|
||||
RecipeManager recipeManager = MinecraftServer.getRecipeManager();
|
||||
sendPacket(recipeManager.getDeclareRecipesPacket());
|
||||
|
||||
List<String> recipesIdentifier = new ArrayList<>();
|
||||
for (Recipe recipe : recipeManager.consumeRecipes(this)) {
|
||||
recipesIdentifier.add(recipe.id());
|
||||
}
|
||||
if (!recipesIdentifier.isEmpty()) {
|
||||
// TODO(1.21.2): Recipes
|
||||
// UnlockRecipesPacket unlockRecipesPacket = new UnlockRecipesPacket(0,
|
||||
// false, false,
|
||||
// false, false,
|
||||
// false, false,
|
||||
// false, false,
|
||||
// recipesIdentifier, recipesIdentifier);
|
||||
// sendPacket(unlockRecipesPacket);
|
||||
}
|
||||
}
|
||||
// Recipes end
|
||||
// Recipes
|
||||
refreshRecipes();
|
||||
|
||||
// Some client updates
|
||||
sendPacket(getPropertiesPacket()); // Send default properties
|
||||
@ -561,6 +541,17 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
|
||||
sendPacket(MinecraftServer.getCommandManager().createDeclareCommandsPacket(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the recipes and recipe book for this player, testing recipe predicates again.
|
||||
*/
|
||||
public void refreshRecipes() {
|
||||
RecipeManager recipeManager = MinecraftServer.getRecipeManager();
|
||||
sendPackets(
|
||||
recipeManager.getDeclareRecipesPacket(),
|
||||
recipeManager.createRecipeBookResetPacket(this)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnGround() {
|
||||
return onGround;
|
||||
|
@ -1,12 +1,19 @@
|
||||
package net.minestom.server.listener;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.client.play.ClientPlaceRecipePacket;
|
||||
import net.minestom.server.network.packet.server.play.PlaceGhostRecipePacket;
|
||||
import net.minestom.server.recipe.RecipeManager;
|
||||
import net.minestom.server.recipe.display.RecipeDisplay;
|
||||
|
||||
public class RecipeListener {
|
||||
|
||||
public static void listener(ClientPlaceRecipePacket packet, Player player) {
|
||||
// TODO(1.21.2)
|
||||
// player.sendPacket(new PlaceGhostRecipePacket(packet.windowId(), packet.recipe()));
|
||||
final RecipeManager recipeManager = MinecraftServer.getRecipeManager();
|
||||
final RecipeDisplay recipeDisplay = recipeManager.getRecipeDisplay(packet.recipeDisplayId(), player);
|
||||
if (recipeDisplay == null) return;
|
||||
|
||||
player.sendPacket(new PlaceGhostRecipePacket(packet.windowId(), recipeDisplay));
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@ import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.NetworkBufferTemplate;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.Ingredient;
|
||||
import net.minestom.server.recipe.RecipeBookCategory;
|
||||
import net.minestom.server.recipe.RecipeSerializers;
|
||||
import net.minestom.server.recipe.display.RecipeDisplay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -30,7 +29,7 @@ public record RecipeBookAddPacket(@NotNull List<Entry> entries, boolean replace)
|
||||
public record Entry(
|
||||
int displayId, @NotNull RecipeDisplay display,
|
||||
@Nullable Integer group, @NotNull RecipeBookCategory category,
|
||||
@Nullable List<Recipe.Ingredient> craftingRequirements,
|
||||
@Nullable List<Ingredient> craftingRequirements,
|
||||
byte flags
|
||||
) {
|
||||
public static final NetworkBuffer.Type<Entry> SERIALIZER = NetworkBufferTemplate.template(
|
||||
@ -38,13 +37,13 @@ public record RecipeBookAddPacket(@NotNull List<Entry> entries, boolean replace)
|
||||
RecipeDisplay.NETWORK_TYPE, Entry::display,
|
||||
NetworkBuffer.OPTIONAL_VAR_INT, Entry::group,
|
||||
RecipeBookCategory.NETWORK_TYPE, Entry::category,
|
||||
RecipeSerializers.INGREDIENT.list().optional(), Entry::craftingRequirements,
|
||||
Ingredient.NETWORK_TYPE.list().optional(), Entry::craftingRequirements,
|
||||
NetworkBuffer.BYTE, Entry::flags,
|
||||
Entry::new);
|
||||
|
||||
public Entry(int displayId, @NotNull RecipeDisplay display,
|
||||
@Nullable Integer group, @NotNull RecipeBookCategory category,
|
||||
@Nullable List<Recipe.Ingredient> craftingRequirements,
|
||||
@Nullable List<Ingredient> craftingRequirements,
|
||||
boolean notification, boolean highlight) {
|
||||
this(displayId, display, group, category, craftingRequirements,
|
||||
(byte) ((notification ? FLAG_NOTIFICATION : 0) | (highlight ? FLAG_HIGHLIGHT : 0)));
|
||||
|
@ -4,8 +4,10 @@ package net.minestom.server.recipe;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.NetworkBufferTemplate;
|
||||
import net.minestom.server.recipe.display.SlotDisplay;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -52,4 +54,15 @@ public record Ingredient(@NotNull List<@NotNull Material> items) {
|
||||
public Ingredient(@NotNull Material @NotNull ... items) {
|
||||
this(List.of(items));
|
||||
}
|
||||
|
||||
public static @Nullable Ingredient fromSlotDisplay(@NotNull SlotDisplay slotDisplay) {
|
||||
return switch (slotDisplay) {
|
||||
case SlotDisplay.Item item -> new Ingredient(item.material());
|
||||
case SlotDisplay.Tag ignored -> {
|
||||
// TODO: Support tags in ingredients (ObjectSet for non static registries)
|
||||
yield null;
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,54 @@
|
||||
package net.minestom.server.recipe;
|
||||
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.recipe.display.RecipeDisplay;
|
||||
import net.minestom.server.recipe.display.SlotDisplay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface Recipe {
|
||||
|
||||
@NotNull RecipeDisplay toDisplay();
|
||||
/**
|
||||
* Creates recipe displays for use in the recipe book.
|
||||
*
|
||||
* <p>Displays should be consistent across calls and not specific to a player, they may be cached in {@link RecipeManager}.</p>
|
||||
*
|
||||
* <p>Note that stonecutter recipes are always sent to the client and not present in the recipe book.
|
||||
* Stonecutter ingredients must be {@link SlotDisplay.Item} or {@link SlotDisplay.Tag} to be shown
|
||||
* on the client.</p>
|
||||
*
|
||||
* @return a list of recipe displays, or none if the recipe should not be displayed in the recipe book
|
||||
*/
|
||||
default @NotNull List<RecipeDisplay> createRecipeDisplays() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol recipe type.
|
||||
* @return
|
||||
* Returns the item properties associated with this recipe. These are sent to the client to indicate
|
||||
* client side special slot prediction. For example, if a recipe includes {@link Material#STONE} in
|
||||
* {@link RecipeProperty#FURNACE_INPUT}, the client will predict that item being placed into a furnace
|
||||
* input (note that final placement is still decided by the server).
|
||||
*
|
||||
* <p>Item properties should be consistent across calls and not specific to a player, they may be cached in {@link RecipeManager}.</p>
|
||||
*
|
||||
* @return A map of item properties associated with this recipe.
|
||||
*/
|
||||
default @Nullable RecipeType recipeType() {
|
||||
default @NotNull Map<RecipeProperty, List<Material>> itemProperties() {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
default @Nullable String recipeBookGroup() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default @Nullable RecipeBookCategory recipeBookCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default @Nullable List<Ingredient> craftingRequirements() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -2,71 +2,137 @@ package net.minestom.server.recipe;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.packet.server.CachedPacket;
|
||||
import net.minestom.server.network.packet.server.SendablePacket;
|
||||
import net.minestom.server.network.packet.server.play.DeclareRecipesPacket;
|
||||
import net.minestom.server.network.packet.server.play.RecipeBookAddPacket;
|
||||
import net.minestom.server.recipe.display.RecipeDisplay;
|
||||
import net.minestom.server.recipe.display.SlotDisplay;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class RecipeManager {
|
||||
private final CachedPacket declareRecipesPacket = new CachedPacket(this::createDeclareRecipesPacket);
|
||||
private final Map<Recipe, Predicate<Player>> recipes = new ConcurrentHashMap<>();
|
||||
private static final AtomicInteger NEXT_DISPLAY_ID = new AtomicInteger();
|
||||
|
||||
private final Int2ObjectMap<RecipeDisplay> displayIdMap = new Int2ObjectArrayMap<>();
|
||||
|
||||
public void addRecipe(@NotNull Recipe recipe, @NotNull Predicate<Player> predicate) {
|
||||
var previous = recipes.put(recipe, predicate);
|
||||
if (previous == null) {
|
||||
declareRecipesPacket.invalidate();
|
||||
}
|
||||
private record RecipeData(
|
||||
@NotNull Recipe recipe,
|
||||
@NotNull List<RecipeBookAddPacket.Entry> displays,
|
||||
@NotNull Predicate<Player> predicate
|
||||
) {
|
||||
}
|
||||
|
||||
private final CachedPacket declareRecipesPacket = new CachedPacket(this::createDeclareRecipesPacket);
|
||||
|
||||
private final Map<Recipe, RecipeData> recipes = new ConcurrentHashMap<>();
|
||||
private final Int2ObjectMap<Map.Entry<RecipeBookAddPacket.Entry, Predicate<Player>>> recipeBookEntryIdMap =
|
||||
Int2ObjectMaps.synchronize(new Int2ObjectArrayMap<>());
|
||||
|
||||
public void addRecipe(@NotNull Recipe recipe) {
|
||||
addRecipe(recipe, player -> true);
|
||||
}
|
||||
|
||||
public void removeRecipe(@NotNull Recipe recipe) {
|
||||
if (this.recipes.remove(recipe) != null) {
|
||||
declareRecipesPacket.invalidate();
|
||||
public void addRecipe(@NotNull Recipe recipe, @NotNull Predicate<Player> predicate) {
|
||||
List<RecipeBookAddPacket.Entry> recipeBookEntries = new ArrayList<>();
|
||||
final RecipeBookCategory recipeBookCategory = recipe.recipeBookCategory();
|
||||
if (recipeBookCategory != null) {
|
||||
for (var display : recipe.createRecipeDisplays()) {
|
||||
int displayId = NEXT_DISPLAY_ID.getAndIncrement();
|
||||
recipeBookEntries.add(new RecipeBookAddPacket.Entry( //todo groups
|
||||
displayId, display, null, recipeBookCategory,
|
||||
recipe.craftingRequirements(), false, false
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
var existingRecipe = recipes.putIfAbsent(recipe, new RecipeData(recipe, recipeBookEntries, predicate));
|
||||
Check.argCondition(existingRecipe != null, "Recipe is already registered: " + recipe);
|
||||
for (RecipeBookAddPacket.Entry entry : recipeBookEntries) {
|
||||
recipeBookEntryIdMap.put(entry.displayId(), Map.entry(entry, predicate));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Recipe> consumeRecipes(Player player) {
|
||||
return recipes.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().test(player))
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
public void removeRecipe(@NotNull Recipe recipe) {
|
||||
final RecipeData removed = recipes.remove(recipe);
|
||||
if (removed != null) {
|
||||
for (var entry : removed.displays) {
|
||||
recipeBookEntryIdMap.remove(entry.displayId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull Set<Recipe> getRecipes() {
|
||||
return recipes.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recipe display for the specified display id, optionally testing visibility against the given player.
|
||||
*
|
||||
* @param displayId the display id
|
||||
* @param player the player to test visibility against, or null to ignore visibility
|
||||
* @return the recipe display, or null if not found or not visible
|
||||
*/
|
||||
public @Nullable RecipeDisplay getRecipeDisplay(int displayId, @Nullable Player player) {
|
||||
var recipeBookEntry = recipeBookEntryIdMap.get(displayId);
|
||||
if (recipeBookEntry == null || (player != null && !recipeBookEntry.getValue().test(player))) return null;
|
||||
|
||||
return recipeBookEntry.getKey().display();
|
||||
}
|
||||
|
||||
public @NotNull SendablePacket getDeclareRecipesPacket() {
|
||||
return declareRecipesPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link RecipeBookAddPacket} which replaces the recipe book with the currently unlocked
|
||||
* recipes for this player.
|
||||
*
|
||||
* @param player the player to create the packet for
|
||||
* @return the recipe book add packet with replace set to true
|
||||
*/
|
||||
public @NotNull RecipeBookAddPacket createRecipeBookResetPacket(@NotNull Player player) {
|
||||
final List<RecipeBookAddPacket.Entry> entries = new ArrayList<>();
|
||||
for (final Map.Entry<Recipe, RecipeData> recipeEntry : recipes.entrySet()) {
|
||||
if (!recipeEntry.getValue().predicate.test(player)) continue;
|
||||
|
||||
entries.addAll(recipeEntry.getValue().displays);
|
||||
}
|
||||
return new RecipeBookAddPacket(entries, true);
|
||||
}
|
||||
|
||||
private @NotNull DeclareRecipesPacket createDeclareRecipesPacket() {
|
||||
// Collect the special recipe entries requested by the client.
|
||||
final Map<RecipeProperty, List<Material>> itemProperties = new HashMap<>();
|
||||
final List<DeclareRecipesPacket.StonecutterRecipe> stonecutterRecipes = new ArrayList<>();
|
||||
for (var recipeDisplay : displayIdMap.values()) {
|
||||
if (recipeDisplay instanceof RecipeDisplay.Stonecutter stonecutterDisplay) {
|
||||
|
||||
|
||||
stonecutterRecipes.add(new DeclareRecipesPacket.StonecutterRecipe(
|
||||
// Ingredient, display
|
||||
))
|
||||
// Collect the item properties for the client
|
||||
final Map<RecipeProperty, Set<Material>> itemProperties = new HashMap<>();
|
||||
for (var recipe : recipes.keySet()) {
|
||||
for (var entry : recipe.itemProperties().entrySet()) {
|
||||
itemProperties.computeIfAbsent(entry.getKey(), k -> new HashSet<>()).addAll(entry.getValue());
|
||||
}
|
||||
}
|
||||
final Map<RecipeProperty, List<Material>> itemPropertiesLists = new HashMap<>();
|
||||
for (var entry : itemProperties.entrySet()) { // Sets to lists
|
||||
itemPropertiesLists.put(entry.getKey(), new ArrayList<>(entry.getValue()));
|
||||
}
|
||||
|
||||
return new DeclareRecipesPacket(itemProperties, stonecutterRecipes);
|
||||
// Collect the stonecutter recipes for the client
|
||||
final List<DeclareRecipesPacket.StonecutterRecipe> stonecutterRecipes = new ArrayList<>();
|
||||
for (var recipeBookEntry : recipeBookEntryIdMap.values()) {
|
||||
if (!(recipeBookEntry.getKey().display() instanceof RecipeDisplay.Stonecutter stonecutterDisplay))
|
||||
continue;
|
||||
|
||||
final Ingredient input = Ingredient.fromSlotDisplay(stonecutterDisplay.ingredient());
|
||||
if (input == null) continue;
|
||||
|
||||
stonecutterRecipes.add(new DeclareRecipesPacket.StonecutterRecipe(input, stonecutterDisplay.result()));
|
||||
}
|
||||
|
||||
return new DeclareRecipesPacket(itemPropertiesLists, stonecutterRecipes);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import net.minestom.server.network.packet.server.login.SetCompressionPacket;
|
||||
import net.minestom.server.network.packet.server.play.*;
|
||||
import net.minestom.server.network.packet.server.status.ResponsePacket;
|
||||
import net.minestom.server.network.player.GameProfile;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.Ingredient;
|
||||
import net.minestom.server.recipe.RecipeBookCategory;
|
||||
import net.minestom.server.recipe.RecipeProperty;
|
||||
import net.minestom.server.recipe.display.RecipeDisplay;
|
||||
@ -97,11 +97,11 @@ public class PacketWriteReadTest {
|
||||
RecipeProperty.BLAST_FURNACE_INPUT, List.of(Material.IRON_HOE, Material.DANDELION),
|
||||
RecipeProperty.SMOKER_INPUT, List.of(Material.STONE),
|
||||
RecipeProperty.CAMPFIRE_INPUT, List.of(Material.STONE)),
|
||||
List.of(new DeclareRecipesPacket.StonecutterRecipe(new Recipe.Ingredient(Material.DIAMOND),
|
||||
List.of(new DeclareRecipesPacket.StonecutterRecipe(new Ingredient(Material.DIAMOND),
|
||||
new SlotDisplay.ItemStack(ItemStack.of(Material.GOLD_BLOCK))))
|
||||
));
|
||||
SERVER_PACKETS.add(new RecipeBookAddPacket(List.of(new RecipeBookAddPacket.Entry(1, recipeDisplay, null,
|
||||
RecipeBookCategory.CRAFTING_MISC, List.of(new Recipe.Ingredient(Material.STONE)), true, true)), false));
|
||||
RecipeBookCategory.CRAFTING_MISC, List.of(new Ingredient(Material.STONE)), true, true)), false));
|
||||
SERVER_PACKETS.add(new RecipeBookRemovePacket(List.of(1)));
|
||||
|
||||
SERVER_PACKETS.add(new DestroyEntitiesPacket(List.of(5, 5, 5)));
|
||||
|
@ -11,11 +11,11 @@ public class IngredientTest {
|
||||
|
||||
@Test
|
||||
public void cannotCreateAirIngredient() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new Recipe.Ingredient(Material.AIR));
|
||||
assertThrows(IllegalArgumentException.class, () -> new Ingredient(Material.AIR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotCreateEmptyIngredient() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new Recipe.Ingredient(List.of()));
|
||||
assertThrows(IllegalArgumentException.class, () -> new Ingredient(List.of()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user