Skip to content
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
35 changes: 35 additions & 0 deletions paper-api/src/main/java/org/bukkit/Bukkit.java
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,19 @@ public static boolean addRecipe(@Nullable Recipe recipe, boolean resendRecipes)
return server.addRecipe(recipe, resendRecipes);
}

/**
* Adds multiple recipes to the crafting manager at once, resending recipes only once
* after all have been added.
*
* @apiNote This method differs from {@link #addRecipe} in that it will only resend the recipe book once instead of once per every recipe added
* @param recipes the recipes to add
* @return true if any recipe was added, false if none were for some reason
* @see #addRecipe
*/
public static boolean addRecipes(@NotNull Iterable<Recipe> recipes) {
return server.addRecipes(recipes);
}

/**
* Get a list of all recipes for a given item. The stack size is ignored
* in comparisons. If the durability is -1, it will match any data value.
Expand Down Expand Up @@ -1312,6 +1325,16 @@ public static void resetRecipes() {
server.resetRecipes();
}

/**
* Checks if the server has a recipe
*
* @param key NamespacedKey of recipe to check for
* @return True if there is a recipe with a matching key
*/
public static boolean hasRecipe(@NotNull NamespacedKey key) {
return server.hasRecipe(key);
}

/**
* Remove a recipe from the server.
*
Expand Down Expand Up @@ -1344,6 +1367,18 @@ public static boolean removeRecipe(@NotNull NamespacedKey key, boolean resendRec
}
// Paper end - method to resend recipes

/**
* Remove multiple recipes from the server.
*
* @apiNote This method differs from {@link #removeRecipe} in that it will only resend the recipe book once instead of once per every recipe removed
* @param keys the NamespacedKeys of the recipes to remove
* @return true if any recipe was removed, false if none were for some reason
* @see #removeRecipe
*/
public static boolean removeRecipes(@NotNull Iterable<NamespacedKey> keys) {
return server.removeRecipes(keys);
}

/**
* Gets a list of command aliases defined in the server properties.
*
Expand Down
29 changes: 29 additions & 0 deletions paper-api/src/main/java/org/bukkit/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,17 @@ default boolean addRecipe(@Nullable Recipe recipe) {
boolean addRecipe(@Nullable Recipe recipe, boolean resendRecipes);
// Paper end - method to send recipes immediately

/**
* Adds multiple recipes to the crafting manager at once, resending recipes only once
* after all have been added.
*
* @apiNote This method differs from {@link #addRecipe} in that it will only resend the recipe book once instead of once per every recipe added
* @param recipes the recipes to add
* @return true if any recipe was added, false if none were for some reason
* @see #addRecipe
*/
boolean addRecipes(@NotNull Iterable<Recipe> recipes);

/**
* Get a list of all recipes for a given item. The stack size is ignored
* in comparisons. If the durability is -1, it will match any data value.
Expand Down Expand Up @@ -1205,6 +1216,14 @@ default ItemStack craftItem(@NotNull ItemStack @NotNull [] craftingMatrix, @NotN
*/
public void resetRecipes();

/**
* Checks if the server has a recipe
*
* @param key NamespacedKey of recipe to check for
* @return True if there is a recipe with a matching key
*/
boolean hasRecipe(@NotNull NamespacedKey key);

/**
* Remove a recipe from the server.
*
Expand Down Expand Up @@ -1235,6 +1254,16 @@ default boolean removeRecipe(@NotNull NamespacedKey key) {
boolean removeRecipe(@NotNull NamespacedKey key, boolean resendRecipes);
// Paper end - method to resend recipes

/**
* Remove multiple recipes from the server.
*
* @apiNote This method differs from {@link #removeRecipe} in that it will only resend the recipe book once instead of once per every recipe removed
* @param keys the NamespacedKeys of the recipes to remove
* @return true if any recipe was removed, false if none were for some reason
* @see #removeRecipe
*/
boolean removeRecipes(@NotNull Iterable<NamespacedKey> keys);

/**
* Gets a list of command aliases defined in the server properties.
*
Expand Down
110 changes: 48 additions & 62 deletions paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
import net.minecraft.world.item.crafting.CraftingInput;
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.RepairItemRecipe;
import net.minecraft.world.level.CustomSpawner;
Expand Down Expand Up @@ -161,21 +162,11 @@
import org.bukkit.craftbukkit.generator.CraftWorldInfo;
import org.bukkit.craftbukkit.generator.OldCraftChunkData;
import org.bukkit.craftbukkit.help.SimpleHelpMap;
import org.bukkit.craftbukkit.inventory.CraftBlastingRecipe;
import org.bukkit.craftbukkit.inventory.CraftCampfireRecipe;
import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
import org.bukkit.craftbukkit.inventory.CraftItemCraftResult;
import org.bukkit.craftbukkit.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.inventory.CraftMerchantCustom;
import org.bukkit.craftbukkit.inventory.CraftRecipe;
import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
import org.bukkit.craftbukkit.inventory.CraftSmithingTransformRecipe;
import org.bukkit.craftbukkit.inventory.CraftSmithingTrimRecipe;
import org.bukkit.craftbukkit.inventory.CraftSmokingRecipe;
import org.bukkit.craftbukkit.inventory.CraftStonecuttingRecipe;
import org.bukkit.craftbukkit.inventory.CraftTransmuteRecipe;
import org.bukkit.craftbukkit.inventory.RecipeIterator;
import org.bukkit.craftbukkit.inventory.util.CraftInventoryCreator;
import org.bukkit.craftbukkit.map.CraftMapColorCache;
Expand Down Expand Up @@ -216,24 +207,13 @@
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.WorldInfo;
import org.bukkit.help.HelpMap;
import org.bukkit.inventory.BlastingRecipe;
import org.bukkit.inventory.CampfireRecipe;
import org.bukkit.inventory.ComplexRecipe;
import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemCraftResult;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Merchant;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe;
import org.bukkit.inventory.SmithingTransformRecipe;
import org.bukkit.inventory.SmithingTrimRecipe;
import org.bukkit.inventory.SmokingRecipe;
import org.bukkit.inventory.StonecuttingRecipe;
import org.bukkit.inventory.TransmuteRecipe;
import org.bukkit.loot.LootTable;
import org.bukkit.map.MapPalette;
import org.bukkit.map.MapView;
Expand Down Expand Up @@ -1440,43 +1420,32 @@ public void savePlayers() {

@Override
public boolean addRecipe(Recipe recipe, boolean resendRecipes) {
CraftRecipe toAdd;
if (recipe instanceof CraftRecipe) {
toAdd = (CraftRecipe) recipe;
} else {
if (recipe instanceof ShapedRecipe) {
toAdd = CraftShapedRecipe.fromBukkitRecipe((ShapedRecipe) recipe);
} else if (recipe instanceof ShapelessRecipe) {
toAdd = CraftShapelessRecipe.fromBukkitRecipe((ShapelessRecipe) recipe);
} else if (recipe instanceof FurnaceRecipe) {
toAdd = CraftFurnaceRecipe.fromBukkitRecipe((FurnaceRecipe) recipe);
} else if (recipe instanceof BlastingRecipe) {
toAdd = CraftBlastingRecipe.fromBukkitRecipe((BlastingRecipe) recipe);
} else if (recipe instanceof CampfireRecipe) {
toAdd = CraftCampfireRecipe.fromBukkitRecipe((CampfireRecipe) recipe);
} else if (recipe instanceof SmokingRecipe) {
toAdd = CraftSmokingRecipe.fromBukkitRecipe((SmokingRecipe) recipe);
} else if (recipe instanceof StonecuttingRecipe) {
toAdd = CraftStonecuttingRecipe.fromBukkitRecipe((StonecuttingRecipe) recipe);
} else if (recipe instanceof SmithingTransformRecipe) {
toAdd = CraftSmithingTransformRecipe.fromBukkitRecipe((SmithingTransformRecipe) recipe);
} else if (recipe instanceof SmithingTrimRecipe) {
toAdd = CraftSmithingTrimRecipe.fromBukkitRecipe((SmithingTrimRecipe) recipe);
} else if (recipe instanceof TransmuteRecipe) {
toAdd = CraftTransmuteRecipe.fromBukkitRecipe((TransmuteRecipe) recipe);
} else if (recipe instanceof ComplexRecipe) {
throw new UnsupportedOperationException("Cannot add custom complex recipe");
} else {
return false;
CraftRecipe craftRecipe = CraftRecipe.fromBukkitRecipe(recipe);
if (craftRecipe == null) {
return false;
}

craftRecipe.addToRecipeManager();
return true;
}

@Override
public boolean addRecipes(Iterable<Recipe> recipes) {
Preconditions.checkArgument(recipes != null, "recipes == null");
boolean anyAdded = false;
RecipeManager recipeManager = this.getServer().getRecipeManager();
for (Recipe recipe : recipes) {
CraftRecipe craftRecipe = CraftRecipe.fromBukkitRecipe(recipe);
if (craftRecipe != null) {
recipeManager.recipes.addRecipe(craftRecipe.toMinecraftRecipe());
anyAdded = true;
}
}
toAdd.addToRecipeManager();
// Paper start - API for updating recipes on clients
if (true || resendRecipes) { // Always needs to be resent now... TODO
this.playerList.reloadRecipes();

if (anyAdded) {
recipeManager.finalizeRecipeLoading();
}
// Paper end - API for updating recipes on clients
return true;
return anyAdded;
}

@Override
Expand Down Expand Up @@ -1648,17 +1617,34 @@ public void resetRecipes() {
}

@Override
public boolean removeRecipe(NamespacedKey recipeKey, boolean resendRecipes) {
public boolean hasRecipe(NamespacedKey recipeKey) {
Preconditions.checkArgument(recipeKey != null, "recipeKey == null");
final ResourceKey<net.minecraft.world.item.crafting.Recipe<?>> id = CraftNamespacedKey.toResourceKey(Registries.RECIPE, recipeKey);
return getServer().getRecipeManager().byKey(id).isPresent();
}

// Paper start - resend recipes on successful removal
@Override
public boolean removeRecipe(NamespacedKey recipeKey, boolean resendRecipes) {
Preconditions.checkArgument(recipeKey != null, "recipeKey == null");
final ResourceKey<net.minecraft.world.item.crafting.Recipe<?>> id = CraftNamespacedKey.toResourceKey(Registries.RECIPE, recipeKey);
final boolean removed = this.getServer().getRecipeManager().removeRecipe(id);
if (removed/* && resendRecipes*/) { // TODO Always need to resend them rn - deprecate this method?
this.playerList.reloadRecipes();
return this.getServer().getRecipeManager().removeRecipe(id);
}

@Override
public boolean removeRecipes(Iterable<NamespacedKey> recipeKeys) {
Preconditions.checkArgument(recipeKeys != null, "recipeKeys == null");
boolean anyRemoved = false;
RecipeManager recipeManager = this.getServer().getRecipeManager();
for (NamespacedKey recipeKey : recipeKeys) {
final ResourceKey<net.minecraft.world.item.crafting.Recipe<?>> id = CraftNamespacedKey.toResourceKey(Registries.RECIPE, recipeKey);
if (recipeManager.recipes.removeRecipe(id)) {
anyRemoved = true;
}
}
if (anyRemoved) {
recipeManager.finalizeRecipeLoading();
}
return removed;
// Paper end - resend recipes on successful removal
return anyRemoved;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@ public static CraftBlastingRecipe fromBukkitRecipe(BlastingRecipe recipe) {
}

@Override
public void addToRecipeManager() {
net.minecraft.world.item.crafting.BlastingRecipe recipe = new net.minecraft.world.item.crafting.BlastingRecipe(
public RecipeHolder<?> toMinecraftRecipe() {
return new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), new net.minecraft.world.item.crafting.BlastingRecipe(
new net.minecraft.world.item.crafting.Recipe.CommonInfo(true),
new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()),
CraftRecipe.toIngredient(this.getInputChoice(), true),
CraftItemStack.asTemplate(this.getResult()),
this.getExperience(),
this.getCookingTime()
);
MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), recipe));
));
}

@Override
public void addToRecipeManager() {
MinecraftServer.getServer().getRecipeManager().addRecipe(toMinecraftRecipe());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import net.minecraft.core.registries.Registries;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.crafting.CampfireCookingRecipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
Expand All @@ -26,15 +25,19 @@ public static CraftCampfireRecipe fromBukkitRecipe(CampfireRecipe recipe) {
}

@Override
public void addToRecipeManager() {
CampfireCookingRecipe recipe = new net.minecraft.world.item.crafting.CampfireCookingRecipe(
public RecipeHolder<?> toMinecraftRecipe() {
return new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), new net.minecraft.world.item.crafting.CampfireCookingRecipe(
new net.minecraft.world.item.crafting.Recipe.CommonInfo(true),
new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()),
CraftRecipe.toIngredient(this.getInputChoice(), true),
CraftItemStack.asTemplate(this.getResult()),
this.getExperience(),
this.getCookingTime()
);
MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), recipe));
));
}

@Override
public void addToRecipeManager() {
MinecraftServer.getServer().getRecipeManager().addRecipe(toMinecraftRecipe());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ public CraftComplexRecipe(NamespacedKey key, ItemStack result, net.minecraft.wor
this.recipe = recipe;
}

@Override
public RecipeHolder<?> toMinecraftRecipe() {
return new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), recipe);
}

@Override
public void addToRecipeManager() {
MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), this.recipe));
MinecraftServer.getServer().getRecipeManager().addRecipe(toMinecraftRecipe());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import net.minecraft.core.registries.Registries;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.SmeltingRecipe;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.inventory.FurnaceRecipe;
Expand All @@ -26,15 +25,19 @@ public static CraftFurnaceRecipe fromBukkitRecipe(FurnaceRecipe recipe) {
}

@Override
public void addToRecipeManager() {
SmeltingRecipe recipe = new net.minecraft.world.item.crafting.SmeltingRecipe(
public RecipeHolder<?> toMinecraftRecipe() {
return new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), new net.minecraft.world.item.crafting.SmeltingRecipe(
new net.minecraft.world.item.crafting.Recipe.CommonInfo(true),
new net.minecraft.world.item.crafting.AbstractCookingRecipe.CookingBookInfo(CraftRecipe.getCategory(this.getCategory()), this.getGroup()),
CraftRecipe.toIngredient(this.getInputChoice(), true),
CraftItemStack.asTemplate(this.getResult()),
this.getExperience(),
this.getCookingTime()
);
MinecraftServer.getServer().getRecipeManager().addRecipe(new RecipeHolder<>(CraftNamespacedKey.toResourceKey(Registries.RECIPE, this.getKey()), recipe));
));
}

@Override
public void addToRecipeManager() {
MinecraftServer.getServer().getRecipeManager().addRecipe(toMinecraftRecipe());
}
}
Loading
Loading