Fixed AutoCrafting & Added 1.16.3 Protocol support

Added 1.16_R2 module
Fixed AutoCrafting by using NMS
This commit is contained in:
James Peters 2020-10-24 15:18:56 +01:00
parent 1c153db2e3
commit 858964c59c
22 changed files with 652 additions and 91 deletions

View File

@ -8,7 +8,7 @@ MAVEN_DIR="$HOME/.m2"
CRAFTBUKKIT="${MAVEN_DIR}/repository/org/bukkit/craftbukkit"
#Versions
array=("1.16.1" "1.15.2" "1.14.4")
array=("1.16.3" "1.16.1" "1.15.2" "1.14.4")
#Download BuildTools jar
curl -s -o BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar

View File

@ -23,11 +23,11 @@ public class Api {
try {
return (NMSProvider) Class.forName(nmsProvider).newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
plugin.getLogger().warning("Loading latest material list from 1.16. If you are running a version later" +
"than this some visual errors may occur on Armour stand displays.");
// plugin.getLogger().warning("A valid server implementation wasn't found for: " + nmsVersion);
// plugin.getLogger().warning("You may be running an outdated version of the plugin or it needs to be updated to the latest version!");
return null;
plugin.getLogger().warning("A valid server implementation wasn't found for: " + nmsVersion);
plugin.getLogger().warning("You may be running an outdated version of the plugin or it needs to be updated to the latest version!");
// Currently depends on NMS for any Crafting abilities
throw new RuntimeException("Currently no NMS version support for "+nmsVersion);
}
}
}

View File

@ -0,0 +1,14 @@
package com.jamesdpeters.minecraft.chests;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import java.util.List;
public interface CraftingProvider {
ItemStack craft(World world, List<ItemStack> items);
Recipe getRecipe(World world, List<ItemStack> items);
}

View File

@ -5,6 +5,7 @@ import org.bukkit.entity.ItemFrame;
public interface NMSProvider {
ChestOpener getChestOpener();
MaterialChecker getMaterialChecker();
CraftingProvider getCraftingProvider();
void setItemFrameVisible(ItemFrame itemFrame, boolean visible);
}

View File

@ -0,0 +1,86 @@
package com.jamesdpeters.minecraft.chests.v1_14_R1;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import net.minecraft.server.v1_14_R1.Container;
import net.minecraft.server.v1_14_R1.EntityHuman;
import net.minecraft.server.v1_14_R1.IRecipe;
import net.minecraft.server.v1_14_R1.InventoryCrafting;
import net.minecraft.server.v1_14_R1.RecipeCrafting;
import net.minecraft.server.v1_14_R1.Recipes;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import java.util.List;
import java.util.Optional;
public class Crafting implements CraftingProvider {
@Override
public ItemStack craft(World world, List<ItemStack> items) {
Container container = new Container(null, -1) {
@Override
public InventoryView getBukkitView() {
return null;
}
@Override
public boolean canUse(EntityHuman entityHuman) {
return false;
}
};
InventoryCrafting crafting = new InventoryCrafting(container, 3, 3);
for (int i = 0; i < items.size(); i++) {
crafting.setItem(i, CraftItemStack.asNMSCopy(items.get(i)));
}
CraftServer server = (CraftServer) Bukkit.getServer();
CraftWorld craftWorld = (CraftWorld) world;
Optional<RecipeCrafting> optional = server.getServer().getCraftingManager().craft(Recipes.CRAFTING, crafting, craftWorld.getHandle());
net.minecraft.server.v1_14_R1.ItemStack itemstack = net.minecraft.server.v1_14_R1.ItemStack.a;
if (optional.isPresent()) {
RecipeCrafting recipeCrafting = optional.get();
itemstack = recipeCrafting.a(crafting);
}
return CraftItemStack.asBukkitCopy(itemstack);
}
@Override
public Recipe getRecipe(World world, List<ItemStack> items) {
Container container = new Container(null, -1) {
@Override
public InventoryView getBukkitView() {
return null;
}
@Override
public boolean canUse(EntityHuman entityHuman) {
return false;
}
};
InventoryCrafting crafting = new InventoryCrafting(container, 3, 3);
for (int i = 0; i < items.size(); i++) {
if(i >= 9) break; // ItemList cant contain more than 9 items.
crafting.setItem(i, CraftItemStack.asNMSCopy(items.get(i)));
}
CraftServer server = (CraftServer) Bukkit.getServer();
CraftWorld craftWorld = (CraftWorld) world;
Optional<RecipeCrafting> optional = server.getServer().getCraftingManager().craft(Recipes.CRAFTING, crafting, craftWorld.getHandle());
return optional.map(IRecipe::toBukkitRecipe).orElse(null);
}
}

View File

@ -1,6 +1,7 @@
package com.jamesdpeters.minecraft.chests.v1_14_R1;
import com.jamesdpeters.minecraft.chests.ChestOpener;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import com.jamesdpeters.minecraft.chests.MaterialChecker;
import com.jamesdpeters.minecraft.chests.NMSProvider;
import org.bukkit.entity.ItemFrame;
@ -16,6 +17,11 @@ public class NMSProviderImpl implements NMSProvider {
return new MaterialChecker_1_14();
}
@Override
public CraftingProvider getCraftingProvider() {
return null;
}
@Override
public void setItemFrameVisible(ItemFrame itemFrame, boolean visible) {
//Not support in 1.14

View File

@ -0,0 +1,86 @@
package com.jamesdpeters.minecraft.chests.v1_15_R1;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import net.minecraft.server.v1_15_R1.Container;
import net.minecraft.server.v1_15_R1.EntityHuman;
import net.minecraft.server.v1_15_R1.IRecipe;
import net.minecraft.server.v1_15_R1.InventoryCrafting;
import net.minecraft.server.v1_15_R1.RecipeCrafting;
import net.minecraft.server.v1_15_R1.Recipes;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_15_R1.CraftServer;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import java.util.List;
import java.util.Optional;
public class Crafting implements CraftingProvider {
@Override
public ItemStack craft(World world, List<ItemStack> items) {
Container container = new Container(null, -1) {
@Override
public InventoryView getBukkitView() {
return null;
}
@Override
public boolean canUse(EntityHuman entityHuman) {
return false;
}
};
InventoryCrafting crafting = new InventoryCrafting(container, 3, 3);
for (int i = 0; i < items.size(); i++) {
crafting.setItem(i, CraftItemStack.asNMSCopy(items.get(i)));
}
CraftServer server = (CraftServer) Bukkit.getServer();
CraftWorld craftWorld = (CraftWorld) world;
Optional<RecipeCrafting> optional = server.getServer().getCraftingManager().craft(Recipes.CRAFTING, crafting, craftWorld.getHandle());
net.minecraft.server.v1_15_R1.ItemStack itemstack = net.minecraft.server.v1_15_R1.ItemStack.a;
if (optional.isPresent()) {
RecipeCrafting recipeCrafting = optional.get();
itemstack = recipeCrafting.a(crafting);
}
return CraftItemStack.asBukkitCopy(itemstack);
}
@Override
public Recipe getRecipe(World world, List<ItemStack> items) {
Container container = new Container(null, -1) {
@Override
public InventoryView getBukkitView() {
return null;
}
@Override
public boolean canUse(EntityHuman entityHuman) {
return false;
}
};
InventoryCrafting crafting = new InventoryCrafting(container, 3, 3);
for (int i = 0; i < items.size(); i++) {
if(i >= 9) break; // ItemList cant contain more than 9 items.
crafting.setItem(i, CraftItemStack.asNMSCopy(items.get(i)));
}
CraftServer server = (CraftServer) Bukkit.getServer();
CraftWorld craftWorld = (CraftWorld) world;
Optional<RecipeCrafting> optional = server.getServer().getCraftingManager().craft(Recipes.CRAFTING, crafting, craftWorld.getHandle());
return optional.map(IRecipe::toBukkitRecipe).orElse(null);
}
}

View File

@ -1,6 +1,7 @@
package com.jamesdpeters.minecraft.chests.v1_15_R1;
import com.jamesdpeters.minecraft.chests.ChestOpener;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import com.jamesdpeters.minecraft.chests.MaterialChecker;
import com.jamesdpeters.minecraft.chests.NMSProvider;
import org.bukkit.entity.ItemFrame;
@ -16,6 +17,11 @@ public class NMSProviderImpl implements NMSProvider {
return new MaterialChecker_1_15();
}
@Override
public CraftingProvider getCraftingProvider() {
return null;
}
@Override
public void setItemFrameVisible(ItemFrame itemFrame, boolean visible) {
//Not supported in 1.15

View File

@ -0,0 +1,86 @@
package com.jamesdpeters.minecraft.chests.v1_16_R1;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import net.minecraft.server.v1_16_R1.Container;
import net.minecraft.server.v1_16_R1.EntityHuman;
import net.minecraft.server.v1_16_R1.IRecipe;
import net.minecraft.server.v1_16_R1.InventoryCrafting;
import net.minecraft.server.v1_16_R1.RecipeCrafting;
import net.minecraft.server.v1_16_R1.Recipes;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_16_R1.CraftServer;
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import java.util.List;
import java.util.Optional;
public class Crafting implements CraftingProvider {
@Override
public ItemStack craft(World world, List<ItemStack> items) {
Container container = new Container(null, -1) {
@Override
public InventoryView getBukkitView() {
return null;
}
@Override
public boolean canUse(EntityHuman entityHuman) {
return false;
}
};
InventoryCrafting crafting = new InventoryCrafting(container, 3, 3);
for (int i = 0; i < items.size(); i++) {
crafting.setItem(i, CraftItemStack.asNMSCopy(items.get(i)));
}
CraftServer server = (CraftServer) Bukkit.getServer();
CraftWorld craftWorld = (CraftWorld) world;
Optional<RecipeCrafting> optional = server.getServer().getCraftingManager().craft(Recipes.CRAFTING, crafting, craftWorld.getHandle());
net.minecraft.server.v1_16_R1.ItemStack itemstack = net.minecraft.server.v1_16_R1.ItemStack.b;
if (optional.isPresent()) {
RecipeCrafting recipeCrafting = optional.get();
itemstack = recipeCrafting.a(crafting);
}
return CraftItemStack.asBukkitCopy(itemstack);
}
@Override
public Recipe getRecipe(World world, List<ItemStack> items) {
Container container = new Container(null, -1) {
@Override
public InventoryView getBukkitView() {
return null;
}
@Override
public boolean canUse(EntityHuman entityHuman) {
return false;
}
};
InventoryCrafting crafting = new InventoryCrafting(container, 3, 3);
for (int i = 0; i < items.size(); i++) {
if(i >= 9) break; // ItemList cant contain more than 9 items.
crafting.setItem(i, CraftItemStack.asNMSCopy(items.get(i)));
}
CraftServer server = (CraftServer) Bukkit.getServer();
CraftWorld craftWorld = (CraftWorld) world;
Optional<RecipeCrafting> optional = server.getServer().getCraftingManager().craft(Recipes.CRAFTING, crafting, craftWorld.getHandle());
return optional.map(IRecipe::toBukkitRecipe).orElse(null);
}
}

View File

@ -1,13 +1,11 @@
package com.jamesdpeters.minecraft.chests.v1_16_R1;
import com.jamesdpeters.minecraft.chests.ChestOpener;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import com.jamesdpeters.minecraft.chests.MaterialChecker;
import com.jamesdpeters.minecraft.chests.NMSProvider;
import com.jamesdpeters.minecraft.chests.TileEntityOpener;
import org.bukkit.block.Container;
import org.bukkit.block.Lidded;
import org.bukkit.entity.ItemFrame;
import org.bukkit.inventory.Inventory;
public class NMSProviderImpl implements NMSProvider {
@ -32,6 +30,11 @@ public class NMSProviderImpl implements NMSProvider {
return new MaterialChecker_1_16();
}
@Override
public CraftingProvider getCraftingProvider() {
return new Crafting();
}
@Override
public void setItemFrameVisible(ItemFrame itemFrame, boolean visible) {
itemFrame.setVisible(visible);

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ChestsPlusPlus-Parent</artifactId>
<groupId>com.jamesdpeters.minecraft.chests</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ChestsPlusPlus_1_16_R2</artifactId>
<version>1.0-SNAPSHOT</version>
<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.jamesdpeters.minecraft.chests</groupId>
<artifactId>ChestsPlusPlus-API</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.16.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.jamesdpeters.minecraft.chests</groupId>
<artifactId>ChestsPlusPlus_1_16</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.16.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,35 @@
package com.jamesdpeters.minecraft.chests.v1_16_R2;
import com.jamesdpeters.minecraft.chests.MaterialChecker;
import com.jamesdpeters.minecraft.chests.v1_16_R1.MaterialChecker_1_16;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.List;
/**
* Only a protocol change from 1.16.2 to 1.16.3 so no new materials were added.
*/
public class MaterialChecker_1_16_R2 extends MaterialChecker {
private MaterialChecker_1_16 version1_16;
public MaterialChecker_1_16_R2(){
version1_16 = new MaterialChecker_1_16();
}
@Override
public List<Material> graphically2DList() {
return version1_16.graphically2DList();
}
@Override
public List<Material> ignoredMaterials() {
return version1_16.ignoredMaterials();
}
@Override
public boolean isTool(ItemStack itemStack) {
return version1_16.isTool(itemStack);
}
}

View File

@ -0,0 +1,51 @@
package com.jamesdpeters.minecraft.chests.v1_16_R2;
import com.jamesdpeters.minecraft.chests.ChestOpener;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import com.jamesdpeters.minecraft.chests.MaterialChecker;
import com.jamesdpeters.minecraft.chests.NMSProvider;
import org.bukkit.block.Lidded;
import org.bukkit.entity.ItemFrame;
public class NMSProviderImpl implements NMSProvider {
@Override
public ChestOpener getChestOpener() {
return (inventory, container, tileEntityOpener) -> {
if(hasLiddedAPI()){
if(container instanceof Lidded){
if(inventory.getViewers().size() > 0){
((Lidded) container).open();
} else {
((Lidded) container).close();
}
}
}
return null;
};
}
@Override
public MaterialChecker getMaterialChecker() {
return new MaterialChecker_1_16_R2();
}
@Override
public CraftingProvider getCraftingProvider() {
return new Crafting();
}
@Override
public void setItemFrameVisible(ItemFrame itemFrame, boolean visible) {
itemFrame.setVisible(visible);
}
private boolean hasLiddedAPI(){
try {
Class.forName("org.bukkit.block.Lidded");
return true;
} catch (ClassNotFoundException e){
return false;
}
}
}

View File

@ -51,7 +51,7 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.14.2-R0.1-SNAPSHOT</version>
<version>1.14.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@ -92,6 +92,14 @@
<version>1.7</version>
</dependency>
<dependency>
<groupId>com.jamesdpeters.minecraft.chests</groupId>
<artifactId>ChestsPlusPlus_1_16_R2</artifactId>
<version>1.0-SNAPSHOT</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.jamesdpeters.minecraft.chests</groupId>
<artifactId>ChestsPlusPlus_1_16</artifactId>

View File

@ -1,6 +1,7 @@
package com.jamesdpeters.minecraft.chests.api;
import com.jamesdpeters.minecraft.chests.ChestOpener;
import com.jamesdpeters.minecraft.chests.CraftingProvider;
import com.jamesdpeters.minecraft.chests.MaterialChecker;
import com.jamesdpeters.minecraft.chests.NMSProvider;
import com.jamesdpeters.minecraft.chests.v1_16_R1.NMSProviderImpl;
@ -27,6 +28,12 @@ public class NMSProviderDefault implements NMSProvider {
return provider1_16.getMaterialChecker();
}
@Override
public CraftingProvider getCraftingProvider() {
// TODO
return null;
}
@Override
public void setItemFrameVisible(ItemFrame itemFrame, boolean visible) {
//Not supported in Bukkit api 1.14.

View File

@ -1,5 +1,6 @@
package com.jamesdpeters.minecraft.chests.crafting;
import com.jamesdpeters.minecraft.chests.api.ApiSpecific;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@ -11,7 +12,6 @@ import org.bukkit.inventory.ShapelessRecipe;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@ -34,26 +34,12 @@ public class Crafting {
});
}
public static Recipe getResult(List<ItemStack> craftingTable) {
Recipe returnRecipe = null;
Iterator<Recipe> iterator = Bukkit.recipeIterator();
while (iterator.hasNext()) {
Recipe recipe = iterator.next();
if (recipe instanceof ShapedRecipe) {
ShapedRecipe shapedRecipe = (ShapedRecipe) recipe;
if (matchesShaped(shapedRecipe, craftingTable)) {
returnRecipe = shapedRecipe;
break;
}
} else if (recipe instanceof ShapelessRecipe) {
ShapelessRecipe shapelessRecipe = (ShapelessRecipe) recipe;
if (matchesShapeless(shapelessRecipe.getChoiceList(), craftingTable)) {
returnRecipe = shapelessRecipe;
break;
}
}
}
return returnRecipe;
public static Recipe getRecipe(List<ItemStack> craftingTable) {
return ApiSpecific.getNmsProvider().getCraftingProvider().getRecipe(Bukkit.getWorlds().get(0), craftingTable);
}
public static ItemStack craft(List<ItemStack> recipe) {
return ApiSpecific.getNmsProvider().getCraftingProvider().craft(Bukkit.getWorlds().get(0), recipe);
}
private static boolean matchesShapeless(List<RecipeChoice> choice, List<ItemStack> items) {

View File

@ -1,13 +0,0 @@
package com.jamesdpeters.minecraft.chests.crafting;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
public class ToolRepairRecipe implements Recipe {
@Override
public ItemStack getResult() {
return null;
}
}

View File

@ -1,6 +1,7 @@
package com.jamesdpeters.minecraft.chests.interfaces;
import com.jamesdpeters.minecraft.chests.ChestsPlusPlus;
import com.jamesdpeters.minecraft.chests.api.ApiSpecific;
import com.jamesdpeters.minecraft.chests.crafting.Crafting;
import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.serialize.Config;
@ -99,9 +100,22 @@ public class VirtualCraftingHolder implements InventoryHolder {
setHasCompleteRecipe();
}
public void setCrafting(Recipe recipe) {
public void setCrafting(Recipe recipe, List<ItemStack> matrix) {
if (recipe instanceof ShapedRecipe) setCrafting((ShapedRecipe) recipe);
if (recipe instanceof ShapelessRecipe) setCrafting((ShapelessRecipe) recipe);
else if (recipe instanceof ShapelessRecipe) setCrafting((ShapelessRecipe) recipe);
else {
// For ComplexRecipes or other implementations just use the result and original matrix for choices.
result = ApiSpecific.getNmsProvider().getCraftingProvider().craft(Bukkit.getWorlds().get(0), matrix);
for (int i = 0; i < matrix.size(); i++) {
ItemStack item = matrix.get(i);
if (item != null) {
recipeChoices[i] = new ItemStack[]{item};
} else {
recipeChoices[i] = null;
}
}
setHasCompleteRecipe();
}
}
private void setHasCompleteRecipe() {
@ -117,17 +131,20 @@ public class VirtualCraftingHolder implements InventoryHolder {
}
public void updateCrafting() {
List<ItemStack> craftingMatrix = new ArrayList<>(Arrays.asList(inventory.getContents()));
if (craftingMatrix.get(0) != null) craftingMatrix.remove(0);
Recipe recipe = Crafting.getResult(craftingMatrix);
getStorage().setRecipe(recipe);
List<ItemStack> crafting = new ArrayList<>(Arrays.asList(inventory.getContents()));
crafting.remove(0);
Recipe recipe = Crafting.getRecipe(crafting);
getStorage().setRecipe(recipe, crafting); // Only store the crafting matrix if the recipe is valid
resetChoices();
if (recipe != null) {
setCrafting(recipe);
setCrafting(recipe, crafting);
playSound(Sound.BLOCK_NOTE_BLOCK_CHIME, 0.5f, 1f);
} else {
stopCraftingItems();
}
isUpdatingRecipe = false;
updateGUI();
storage.onItemDisplayUpdate(result);
@ -276,9 +293,105 @@ public class VirtualCraftingHolder implements InventoryHolder {
return inventory;
}
private int getRecipeChoiceAmount() {
int max = 0;
for (ItemStack[] recipeChoice : recipeChoices) {
if (recipeChoice != null && recipeChoice.length > max){
max = recipeChoice.length;
}
}
return max;
}
/**
* Finds a valid recipe matrix for the currently selected recipe.
* Removes the items from the inventories provided.
* @param inventories
* @return a valid recipe matrix selected from the inventories provided.
*/
private List<ItemStack> getRecipeMatrix(List<Inventory> inventories) {
// Loop through recipe choice array to find recipeChoice index.
int recipeChoicesAmount = getRecipeChoiceAmount();
// Bukkit.broadcastMessage("Recipe choices: "+recipeChoicesAmount);
for (int recipeChoiceIndex = 0; recipeChoiceIndex < recipeChoicesAmount; recipeChoiceIndex++) {
// Store each item selected for the recipe.
// This is used to retrieve the actual result taking into account meta data, such as repairing items.
List<ItemStack> tempRecipe = Utils.createAirList(9);
int recipeIndex = 0;
// Need a new copy of the inventories to test for each recipe choice.
List<Inventory> tempInvs = Utils.copyInventoryList(inventories);
// Bukkit.broadcastMessage("Recipe choices in loop: "+ Arrays.deepToString(recipeChoices));
// Loops over each slot of the matrix
for (ItemStack[] choices : recipeChoices) {
// If there's no recipe choice at this index skip and set the matrix pos to null
if (choices == null){
tempRecipe.set(recipeIndex, null);
recipeIndex++;
} else { // Otherwise check for a valid item for this recipe choice.
// Select the current recipeChoice
ItemStack choice = choices[recipeChoiceIndex];
boolean foundMatch = false;
for (Inventory tempInv : tempInvs) {
int index = tempInv.first(choice.getType());
if (index != -1) {
ItemStack item = tempInv.getItem(index);
if (item != null) {
// If a valid item has been found in one of the inventories.
ItemStack selectedItem = item.clone();
item.setAmount(item.getAmount() - 1);
tempInv.setItem(index, item);
selectedItem.setAmount(1);
tempRecipe.set(recipeIndex, selectedItem);
recipeIndex++;
foundMatch = true;
break;
}
}
}
//If no match found
if (!foundMatch) {
break;
}
}
// Completed the matrix
if ((recipeIndex >= recipeChoices.length)) {
// Move temp invs to input invs.
for (int i = 0; i < tempInvs.size(); i++) {
moveTempInv(tempInvs.get(i), inventories.get(i));
}
return tempRecipe;
}
}
}
return null;
}
private boolean craftItem(List<Inventory> inputs, Inventory output) {
boolean sameInv = false;
Inventory sameInventory = null;
// Create a copy of the real inventories and decide if any of the inputs match the output.
List<Inventory> tempInvs = new ArrayList<>();
for (Inventory inv : inputs) {
@ -290,31 +403,17 @@ public class VirtualCraftingHolder implements InventoryHolder {
}
}
for (ItemStack[] choices : recipeChoices) {
if (choices == null) continue;
boolean foundMatch = false;
for (ItemStack choice : choices) {
for (Inventory tempInv : tempInvs) {
int index = tempInv.first(choice.getType());
if (index != -1) {
ItemStack item = tempInv.getItem(index);
if (item != null) {
item.setAmount(item.getAmount() - 1);
tempInv.setItem(index, item);
foundMatch = true;
break;
}
}
}
}
//If no match
if (!foundMatch) return false;
}
List<ItemStack> recipe = getRecipeMatrix(tempInvs);
// null recipe means no recipe was found from the inventories.
if (recipe == null) return false;
// Use NMS to get the real result considering meta data etc.
ItemStack realResult = Crafting.craft(recipe);
//If we reach here there are enough materials so check for space in the Hopper and update inventory.
//Check if output and input are the same inventory to avoid duplication.
Inventory tempOutput = sameInv ? sameInventory : Utils.copyInventory(output);
HashMap map = tempOutput.addItem(result.clone());
HashMap<Integer, ItemStack> map = tempOutput.addItem(realResult);
//If result fits into output copy over the temporary inventories.
if (map.isEmpty()) {

View File

@ -20,15 +20,12 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Container;
import org.bukkit.block.Hopper;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.Vector;
@ -202,6 +199,24 @@ public class Utils {
return tempInv;
}
public static List<Inventory> copyInventoryList(List<Inventory> inventories) {
List<Inventory> tempInvs = new ArrayList<>();
for (Inventory inv : inventories) {
Inventory tempInv = Utils.copyInventory(inv);
tempInvs.add(tempInv);
}
return tempInvs;
}
public static List<ItemStack> createAirList(int size) {
List<ItemStack> itemStacks = new ArrayList<>();
ItemStack AIR = new ItemStack(Material.AIR);
for (int i = 0; i < size; i++) {
itemStacks.add(AIR);
}
return itemStacks;
}
/**
* Removes all entities that contain a value of 1 under the Values.PluginKey key.
* Updates all Item Frames with invisibility status.

View File

@ -1,41 +1,62 @@
package com.jamesdpeters.minecraft.chests.serialize;
import com.jamesdpeters.minecraft.chests.api.ApiSpecific;
import com.jamesdpeters.minecraft.chests.crafting.Crafting;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@SerializableAs("C++Recipe")
public class RecipeSerializable implements ConfigurationSerializable {
private final Recipe recipe;
private final NamespacedKey key;
private Recipe recipe;
private NamespacedKey namespacedKey;
public RecipeSerializable(Recipe recipe) {
// Store items used for ComplexRecipes
private List<ItemStack> items;
public RecipeSerializable(Recipe recipe, List<ItemStack> items) {
this.recipe = recipe;
if (recipe instanceof ShapedRecipe) key = ((ShapedRecipe) recipe).getKey();
else if (recipe instanceof ShapelessRecipe) key = ((ShapelessRecipe) recipe).getKey();
else
throw new IllegalArgumentException("Recipe type has not been implemented! " + recipe.getClass().toGenericString());
this.items = items;
if (recipe instanceof Keyed){
namespacedKey = ((Keyed) recipe).getKey();
}
}
public RecipeSerializable(Map<String, Object> map) {
Object obj = map.get("items");
if (obj != null) {
//noinspection unchecked
items = (List<ItemStack>) obj;
}
//noinspection deprecation
key = new NamespacedKey((String) map.get("namespace"), (String) map.get("key"));
recipe = Crafting.getRecipeByKey(key);
namespacedKey = new NamespacedKey((String) map.get("namespace"), (String) map.get("key"));
recipe = Crafting.getRecipeByKey(namespacedKey);
if (recipe == null) {
recipe = ApiSpecific.getNmsProvider().getCraftingProvider().getRecipe(Bukkit.getWorlds().get(0), items);
}
}
@Override
public Map<String, Object> serialize() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("namespace", key.getNamespace());
map.put("key", key.getKey());
map.put("namespace", namespacedKey.getNamespace());
map.put("key", namespacedKey.getKey());
if (!(recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe)) {
map.put("items", items);
}
return map;
}
@ -43,7 +64,11 @@ public class RecipeSerializable implements ConfigurationSerializable {
return recipe;
}
public NamespacedKey getKey() {
return key;
public NamespacedKey getNamespacedKey() {
return namespacedKey;
}
public List<ItemStack> getItems() {
return items;
}
}

View File

@ -12,10 +12,12 @@ import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe;
import java.util.List;
import java.util.Map;
@SerializableAs("AutoCraftingStorage")
@ -58,12 +60,12 @@ public class AutoCraftingStorage extends AbstractStorage implements Configuratio
return false;
}
public void setRecipe(Recipe recipe) {
public void setRecipe(Recipe recipe, List<ItemStack> items) {
if (recipe == null) {
recipeSerializable = null;
return;
}
recipeSerializable = new RecipeSerializable(recipe);
recipeSerializable = new RecipeSerializable(recipe, items);
}
@Override
@ -100,9 +102,12 @@ public class AutoCraftingStorage extends AbstractStorage implements Configuratio
if (recipe instanceof ShapelessRecipe) {
virtualCraftingHolder.setCrafting((ShapelessRecipe) recipe);
}
if (recipe instanceof ShapedRecipe) {
else if (recipe instanceof ShapedRecipe) {
virtualCraftingHolder.setCrafting((ShapedRecipe) recipe);
}
else {
virtualCraftingHolder.setCrafting(recipe, recipeSerializable.getItems());
}
} else {
virtualCraftingHolder.resetChoices();
}

View File

@ -16,6 +16,7 @@
<modules>
<module>ChestsPlusPlusAPI</module>
<module>ChestsPlusPlus_1_16_R2</module>
<module>ChestsPlusPlus_1_16</module>
<module>ChestsPlusPlus_1_15</module>
<module>ChestsPlusPlus_1_14</module>